Skip to content

JonathanFly/chirp-studio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 

Repository files navigation

Suno Music Tweaks

Little one-off scripts I wrote for myself I may as well share.

  1. Simple Wavform and Volume Bookmarklet
  2. Audio Visualizer Chrome Extension (not working: needs to be updated to work with new Suno website)
  3. UI Tweak Bookmarket: add custom notes to each track, direct song part links, create data and duration metadata. (not working at the moment)

1. Simple Wavform and Volume

image

  1. Pick "Add New Bookmark" in Booksmarks Manager (or "Add Page" in the bookmark bar)
  2. Bookmark Name: "Suno Wavform" (whatever you want)
  3. Bookmark URL: copy the block of code below that starts with "javascript" including the word javascript.
  4. On Chirp library page, click this newly added bookmark link. Then play a song.
  5. You have to click the bookmarklet link every time you open the Suno web site to enable this.
javascript:(function()%7Bconst%20loadWavesurfer%20%3D%20()%20%3D%3E%20%7B%0A%20%20%20%20if%20(!window.WaveSurfer)%20%7B%0A%20%20%20%20%20%20const%20script%20%3D%20document.createElement('script')%3B%0A%20%20%20%20%20%20script.src%20%3D%20'https%3A%2F%2Funpkg.com%2Fwavesurfer.js'%3B%0A%20%20%20%20%20%20document.head.appendChild(script)%3B%0A%20%20%20%20%20%20script.onload%20%3D%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20initWaveSurfer()%3B%0A%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20initWaveSurfer()%3B%0A%20%20%20%20%7D%0A%20%20%7D%3B%0A%20%20%0A%20%20const%20initWaveSurfer%20%3D%20()%20%3D%3E%20%7B%0A%20%20%20%20const%20audioElement%20%3D%20document.querySelector('audio')%3B%0A%20%20%20%20%20%20%20%20const%20waveContainer%20%3D%20document.createElement('div')%3B%0A%20%20%20%20waveContainer.id%20%3D%20'waveformdiv'%3B%0A%0A%0A%20%20%20%20const%20SunoSlider%20%3D%20document.querySelector('.chakra-slider')%3B%0A%20%20%20%20%0A%20%20%20%20SunoSlider.appendChild(waveContainer)%3B%0A%20%20%20%20%0A%20%20%20%20const%20wavesurfer%20%3D%20WaveSurfer.create(%7B%0A%20%20%20%20%20%20container%3A%20waveContainer%2C%0A%20%20%20%20%20%20waveColor%3A%20'violet'%2C%0A%20%20%20%20%20%20progressColor%3A%20'purple'%2C%0A%20%20%20%20%20%20barWidth%3A%201%2C%0A%20%20%20%20%20%20barGap%3A%200.5%2C%0A%20%20%20%20%20%20cursorWidth%3A%201%2C%0A%20%20%20%20%20%20backend%3A%20'MediaElement'%2C%0A%20%20%20%20%20%20%2F%2F%20mediaControls%3A%20true%0A%20%20%20%20%7D)%3B%0A%20%20%0A%0A%20%20%20%20wavesurfer.load(audioElement.src)%3B%0A%20%20%20%20%20%20new%20MutationObserver(()%20%3D%3E%20wavesurfer.load(audioElement.src))%0A%20%20%20%20%20%20.observe(audioElement%2C%20%7B%20attributes%3A%20true%2C%20attributeFilter%3A%20%5B'src'%5D%20%7D)%3B%0A%20%20%0A%20%20%20%20addVolumeControl(wavesurfer%2C%20waveContainer)%3B%0A%20%20%20%20addSpeedControl(wavesurfer%2C%20waveContainer)%3B%0A%20%20%7D%3B%0A%0Aconst%20addVolumeControl%20%3D%20(wavesurfer%2C%20container)%20%3D%3E%20%7B%0A%20%20%20%20if%20(!wavesurfer)%20return%3B%0A%0A%20%20%20%20const%20volumeControl%20%3D%20document.createElement('input')%3B%0A%20%20%20%20volumeControl.type%20%3D%20'range'%3B%0A%20%20%20%20volumeControl.min%20%3D%200%3B%0A%20%20%20%20volumeControl.max%20%3D%201%3B%0A%20%20%20%20volumeControl.step%20%3D%200.01%3B%0A%20%20%20%20volumeControl.value%20%3D%20wavesurfer.getVolume()%3B%0A%20%20%20%20volumeControl.title%20%3D%20'Volume'%3B%0A%20%20%20%20volumeControl.name%20%3D%20'Volume'%3B%0A%20%20%20%20volumeControl.classList.add('volume-control')%3B%20%2F%2F%20Add%20class%20for%20styling%0A%20%20%20%20volumeControl.addEventListener('input'%2C%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20wavesurfer.setVolume(volumeControl.value)%3B%0A%20%20%20%20%20%20audioElement.volume%20%3D%20volumeControl.value%3B%0A%0A%20%20%20%20%7D)%3B%0A%0A%20%20%20%20containerParent%20%3D%20container.parentElement.parentElement%3B%0A%20%20%20%20containerParent.appendChild(volumeControl)%3B%0A%7D%3B%0A%0Aconst%20addSpeedControl%20%3D%20(wavesurfer%2C%20container)%20%3D%3E%20%7B%0A%20%20%20%20if%20(!wavesurfer)%20return%3B%0A%0A%20%20%20%20const%20speedControlContainer%20%3D%20document.createElement('div')%3B%0A%20%20%20%20speedControlContainer.classList.add('speed-control-container')%3B%0A%0A%20%20%20%20const%20speedControl%20%3D%20document.createElement('input')%3B%0A%20%20%20%20speedControl.type%20%3D%20'range'%3B%0A%20%20%20%20speedControl.min%20%3D%200.5%3B%0A%20%20%20%20speedControl.max%20%3D%202%3B%0A%20%20%20%20speedControl.step%20%3D%200.1%3B%0A%20%20%20%20speedControl.value%20%3D%20wavesurfer.getPlaybackRate()%3B%0A%20%20%20%20speedControl.classList.add('speed-control')%3B%20%0A%0A%20%20%20%20const%20speedDisplay%20%3D%20document.createElement('span')%3B%0A%20%20%20%20speedDisplay.classList.add('speed-display')%3B%0A%20%20%20%20speedDisplay.textContent%20%3D%20%60Speed%3A%20%24%7BspeedControl.value%7D%60%3B%0A%0A%20%20%20%20speedControl.addEventListener('input'%2C%20()%20%3D%3E%20%7B%0A%20%20%20%20%20%20wavesurfer.setPlaybackRate(speedControl.value)%3B%0A%20%20%20%20%20%20audioElement.playbackRate%20%3D%20speedControl.value%3B%0A%0A%20%20%20%20%20%20speedDisplay.textContent%20%3D%20%60Speed%3A%20%24%7BparseFloat(speedControl.value).toFixed(2)%7D%60%3B%0A%20%20%20%20%7D)%3B%0A%0A%20%20%20%20speedControlContainer.appendChild(speedControl)%3B%0A%20%20%20%20speedControlContainer.appendChild(speedDisplay)%3B%0A%0A%20%20%20%20containerParent%20%3D%20container.parentElement.parentElement%3B%0A%0A%20%20%20%20containerParent.appendChild(speedControlContainer)%3B%0A%7D%3B%0A%0Aconst%20addStyles%20%3D%20()%20%3D%3E%20%7B%0A%20%20const%20style%20%3D%20document.createElement('style')%3B%0A%20%20style.innerHTML%20%3D%20%60%0A%20%20%23waveformdiv%20%7B%0A%20%20%20%20width%3A%20100%25%3B%0A%20%20%20%20position%3A%20absolute%3B%0A%20%20%20%20top%3A%20-120px%3B%0A%20%20%7D%0A%0A%20%20.volume-control%2C%20.speed-control%2C%20.speed-control-container%20%7B%0A%20%20%20%20margin%3A%2010px%200%3B%0A%20%20%20%20position%3A%20absolute%3B%0A%0A%20%20%20%0A%20%20%7D%0A.speed-control%20%7B%0A%20%20left%3A%2030%25%3B%0A%7D%0A%0Aspan.speed-display%20%7B%0A%20%20position%3A%20absolute%3B%0A%20%20%20%20font-size%3A%2014px%3B%0A%20%20%20%20top%3A%20-11px%3B%0A%20%20%20%20width%3A%2080px%3B%0A%7D%0A%20%20.volume-control%20%7B%0A%20%20%20%20left%3A%20450px%3B%0A%20%20%20%20width%3A%20100px%3B%0A%20%20%7D%0A%20%20.speed-control-container%20%7B%0A%20%20%20%20align-items%3A%20center%3B%0A%20%20%20%20left%3A%2030%25%3B%0A%20%20%20%20bottom%3A%2042px%3B%0A%20%20%7D%0A%20%20.speed-display%20%7B%0A%20%20%20%20margin-left%3A%2010px%3B%0A%20%20%7D%0A%60%3B%0A%0A%0A%20%20document.head.appendChild(style)%3B%0A%7D%3B%0A%0Aconst%20audioElement%20%3D%20document.querySelector('audio')%3B%0AloadWavesurfer()%3B%0AaddStyles()%3B%7D)()%3B

2. Chrome Extension Audio Visualizer for Suno's Chirp Music AI

"I wonder if I can get a Chirp visualizer working in less than an hour..."

image

Install

  1. Download zip https://github.com/JonathanFly/chirp-studio/releases
  2. Extract files
  3. Chrome -> Extensions -> Load Unpacked -> Pick folder "chirp-studio-chrome-extension"
chirp-studio-chrome-extension.mp4

Might have to refresh on the Chirp site, there's no proper load order code. Just a big blob of javasscript.

3. Jonathan's Janky Chirp UI Tweaks

Bit of code to make it easier to deal with large Chirp libraries.

  1. Show song creation date and song duration.
  2. Directly link to the previous clips making up a full song.
  3. Add custom user notes to any song.

chirp_tweaks

How to use this bookmarket

  1. Pick "Add New Bookmark" in Booksmarks Manager (or "Add Page" in the bookmark bar)
  2. Bookmark Name: "Chirp Tweaks" (whatever name you want)
  3. Bookmark URL: copy the block of code below that starts with "javascript" including the word javascript.
  4. On Chirp website, click this newly added bookmark link. Then navigate through your library, after the page loads, the script will add the extra metadata to each song. You will have to click the bookmark each new time you go to the site, but any notes added to songs will persist.

This is just a big yarn ball of javascript on a timer, but it does work on my system. (I'm not sure if one still works.)

javascript:(function()%7B(function()%20%7B%0A%20%20%20%20const%20originalFetch%20%3D%20window.fetch%3B%0A%0A%20%20%20%20window.fetch%20%3D%20function()%20%7B%0A%20%20%20%20%20%20%20%20return%20originalFetch.apply(this%2C%20arguments).then(response%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(response.url.includes('api%2Ffeed'))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20response.clone().json().then(json%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20%3D%3E%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20json.forEach(item%20%3D%3E%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.log(%60%24%7Bitem.id%7D%60)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20linkSelector%20%3D%20%60a.chakra-link%5Bhref%3D%22%2Fsong%2F%24%7Bitem.id%7D%2F%22%5D%60%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20linkElement%20%3D%20document.querySelector(linkSelector)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(linkElement%20%26%26%20!linkElement.classList.contains('processed-item'))%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20parentElement%20%3D%20linkElement.parentElement%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20targetDiv%20%3D%20parentElement.parentElement.parentElement.parentElement.parentElement%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20buttonDiv%20%3D%20parentElement.parentElement.parentElement.parentElement%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20parentDiv%20%3D%20parentElement%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(parentDiv)%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20linkElement.classList.add('processed-item')%3B%0A%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20collapseBtn%20%3D%20document.createElement('button')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20collapseBtn.innerText%20%3D%20'hide%E2%99%BB%EF%B8%8F'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20collapseBtn.classList.add('collapse-btn')%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20collapseBtn.addEventListener('click'%2C%20function()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20isCollapsed%20%3D%20targetDiv.classList.toggle('collapsed')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20localStorage.setItem(%60song_collapse_state_%24%7Bitem.id%7D%60%2C%20isCollapsed)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20savedCollapseState%20%3D%20localStorage.getItem(%60song_collapse_state_%24%7Bitem.id%7D%60)%20%3D%3D%3D%20'true'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(savedCollapseState)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20targetDiv.classList.add('collapsed')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20targetDiv.insertBefore(collapseBtn%2C%20targetDiv.firstChild)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20dateElement%20%3D%20document.createElement('span')%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20history%20%3D%20item.metadata.history%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20concat_history%20%3D%20item.metadata.concat_history%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20audio_prompt_id%20%3D%20item.metadata.audio_prompt_id%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20historyContent%20%3D%20''%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20some_history%20%3D%20%5B%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(Boolean(history))%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20some_history%20%3D%20some_history.concat(history)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(Boolean(concat_history))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20some_history%20%3D%20some_history.concat(concat_history)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(Boolean(some_history))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(var%20i%20%3D%20some_history.length-1%3B%20i%20%3E%3D%200%3B%20i--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20historyItem%20%3D%20some_history%5Bi%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20historyItemElement%20%3D%20document.createElement('span')%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20styleb%20%3D%20%22background%3A%20rgb(63%2C%2069%2C%2099)%3B%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(historyItem%5BhistoryItem.length-2%5D%20%3D%3D%3D%20%22_%22)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20styleb%20%3D%20%22background%3A%20%23000000%3B%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20historyContent%20%2B%3D%20%60%3Ca%20href%3D%22%2Fsong%2F%24%7BhistoryItem%7D%2F%22%20class%3D%22css-18etihr%22%20style%3D%22%24%7Bstyleb%7D%22%3EPart%20%24%7Bi%2B1%7D%3C%2Fa%3E%20%60%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20duration%20%3D%20item.metadata.duration%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(duration%20%3D%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20duration%20%3D%20'Full%20Song'%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20duration%20%3D%20%60%24%7Bduration%7Ds%60%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20storedNotes%20%3D%20localStorage.getItem(%60song_notes_%24%7Bitem.id%7D%60)%20%7C%7C%20''%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20notesInput%20%3D%20%60%3Ctextarea%20style%3D%22border%3A%202px%20dashed%20rgb(247%20228%20143%20%2F%2048%25)%3B%20width%3A%2080%25%3B%20padding%3A%200px%205px%3B%20overflow-y%3A%20hidden%3B%20height%3A%2025px%3B%20max-height%3A%20160px%3B%20%20%20%20%20color%3A%20%23f7f0bc%3B%22%20class%3D%22chakra-textarea%20css-ca7733%20songnotes%22%20placeholder%3D%22Your%20song%20notes%20here%22%20id%3D%22notes_%24%7Bitem.id%7D%22%3E%24%7BstoredNotes%7D%3C%2Ftextarea%3E%60%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dateElement.innerHTML%20%3D%20%60%3Cp%20data-theme%3D%22dark%22%20style%3D%22font-size%3A%2015px%3B%20color%3A%20%23ff0000c7%22%3E%24%7Bduration%7D%20%3Cspan%20style%3D%22font-size%3A%2012px%3B%20color%3A%20%23ff8400%3B%22%3E%24%7Bnew%20Date(item.created_at).toLocaleDateString()%7D%20%24%7Bnew%20Date(item.created_at).toLocaleTimeString()%7D%3C%2Fspan%3E%20%24%7BhistoryContent%7D%20%3C%2Fp%3E%20%3Cp%20data-theme%3D%22dark%22%3E%24%7BnotesInput%7D%3C%2Fp%3E%60%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20parentDiv.insertBefore(dateElement%2C%20parentDiv.firstChild)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20document.getElementById(%60notes_%24%7Bitem.id%7D%60).addEventListener('change'%2C%20function()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20localStorage.setItem(%60song_notes_%24%7Bitem.id%7D%60%2C%20this.value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%201500)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20response%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D).catch(error%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20console.error('Error%20parsing%20JSON%3A'%2C%20error)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20response%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20%2F%2F%20CSS%20for%20collapsed%20state%0A%20%20%20%20const%20style%20%3D%20document.createElement('style')%3B%0A%20%20%20%20style.innerHTML%20%3D%20%60%0A%20%20%20%20%20%20%20%20.collapsed%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20padding%3A%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20margin%3A%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3A%2022px%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20overflow%3A%20hidden%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20vertical-align%3A%20top%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20flex-direction%3A%20column-reverse%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%60%3B%0A%20%20%20%20document.head.appendChild(style)%3B%0A%7D)()%3B%7D)()%3B