Created
October 2, 2024 16:37
-
-
Save esauvisky/baf49c8b5451c89aee487ce59ae50df4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Udio Song Settings Extractor | |
// @namespace http://tampermonkey.net/ | |
// @version 1.3 | |
// @description Extracts and displays Udio song generation settings and sampler options from a UUID in the meta tag with styled list items | |
// @author emi (https://emi.do) | |
// @match https://www.udio.com/songs/* | |
// @match https://www.udio.com/create | |
// @grant GM_xmlhttpRequest | |
// @run-at document-end | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
/** | |
* Extract UUID from the provided URL using regex. | |
* @param {string} url - The URL string to extract UUID from. | |
* @returns {string|null} - The extracted UUID or null if not found. | |
*/ | |
function extractUUID(url) { | |
const match = url.match(/embed\/([a-zA-Z0-9-]{36})/); | |
return match ? match[1] : null; | |
} | |
/** | |
* Create and append the settings container to the specified parent element. | |
* @param {Object} combinedSettings - The combined generation settings and sampler options. | |
* @param {HTMLElement} parentElement - The DOM element to append the settings to. | |
*/ | |
function appendSettings(combinedSettings, parentElement) { | |
if (!parentElement) { | |
console.warn('Parent element for settings not found.'); | |
return; | |
} | |
const settingsContainer = document.createElement('div'); | |
settingsContainer.style.marginTop = '10px'; | |
for (const [key, value] of Object.entries(combinedSettings)) { | |
const settingDiv = document.createElement('div'); | |
try { | |
value = JSON.parse(value); | |
console.log("parsed " + value); | |
} catch (e) {} | |
settingDiv.className = 'border-white/opacity-10 mx-4 mb-4 flex rounded-lg border px-4 py-3 md:mx-0 md:mb-3 md:border-none md:px-0 md:py-0'; | |
settingDiv.innerHTML = ` | |
<div class="flex flex-1 flex-col"> | |
<div class="mb-2 text-base text-brand-gray-light md:hidden">${key}</div> | |
<div class="items-center md:flex"> | |
<div class="text-base font-normal leading-5 text-muted-foreground"> | |
<span class="hidden text-sm md:block ">${key}: ${JSON.stringify(value, null, 4)}</span> | |
</div> | |
</div> | |
</div> | |
`; | |
settingsContainer.appendChild(settingDiv); | |
} | |
parentElement.appendChild(settingsContainer); | |
} | |
/** | |
* Fetch settings from the API and append them to the DOM. | |
* @param {string} uuid - The UUID of the song. | |
*/ | |
function fetchAndDisplaySettings(uuid) { | |
const apiUrl = `https://www.udio.com/api/songs/${uuid}/settings`; | |
console.log("Making request to " + apiUrl); | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: apiUrl, | |
onload: function (response) { | |
if (response.status === 200) { | |
try { | |
const result = JSON.parse(response.responseText); | |
const combinedSettings = { | |
...result.generationSettings, | |
...result.samplerOptions | |
}; | |
const tagLink = document.querySelector('a[href^="/tags"]'); | |
if (tagLink) { | |
const parentElement = tagLink.parentElement; | |
appendSettings(combinedSettings, parentElement); | |
} | |
} catch (error) { | |
console.error("Error parsing API response:", error); | |
} | |
} else { | |
console.error(`Failed to fetch settings. Status: ${response.status}`); | |
} | |
}, | |
onerror: function (error) { | |
console.error("GM_xmlhttpRequest failed:", error); | |
} | |
}); | |
} | |
/** | |
* Initialize settings extraction on page load by checking the meta tag. | |
*/ | |
function initializeOnPageLoad() { | |
const metaTag = document.querySelector('meta[name="twitter:player"]'); | |
if (metaTag) { | |
const contentUrl = metaTag.getAttribute('content'); | |
const uuid = extractUUID(contentUrl); | |
if (uuid) { | |
fetchAndDisplaySettings(uuid); | |
} else { | |
console.warn("UUID not found in meta tag content."); | |
} | |
} | |
} | |
/** | |
* Add click event listeners to track detail links to fetch and display settings dynamically. | |
*/ | |
function initializeTrackDetailListeners() { | |
const targetSelector = 'a[aria-description="open track details preview"]'; | |
/** | |
* Handler for when a track detail link is clicked. | |
* @param {Event} event - The click event. | |
*/ | |
function handleTrackDetailClick(event) { | |
event.preventDefault(); | |
const link = event.currentTarget; | |
const shortUuid = link.href.split('/').pop(); | |
const songUrl = `https://www.udio.com/songs/${shortUuid}`; | |
GM_xmlhttpRequest({ | |
method: "GET", | |
url: songUrl, | |
onload: function (response) { | |
if (response.status === 200) { | |
const parser = new DOMParser(); | |
const doc = parser.parseFromString(response.responseText, "text/html"); | |
const metaTag = doc.querySelector('meta[name="twitter:player"]'); | |
if (metaTag) { | |
const contentUrl = metaTag.getAttribute('content'); | |
const longUuid = extractUUID(contentUrl); | |
if (longUuid) { | |
fetchAndDisplaySettings(longUuid); | |
} else { | |
console.warn("Long UUID not found in song page meta tag."); | |
} | |
} else { | |
console.warn("Meta tag 'twitter:player' not found in song page."); | |
} | |
} else { | |
console.error(`Failed to fetch song page. Status: ${response.status}`); | |
} | |
}, | |
onerror: function (error) { | |
console.error("GM_xmlhttpRequest failed:", error); | |
} | |
}); | |
} | |
/** | |
* Observe the DOM for addition of target track detail links and attach listeners. | |
*/ | |
function observeTrackDetailLinks() { | |
const observer = new MutationObserver((mutations) => { | |
for (const mutation of mutations) { | |
if (mutation.type === 'childList') { | |
mutation.addedNodes.forEach(node => { | |
if (node.nodeType === Node.ELEMENT_NODE) { | |
const links = node.matches(targetSelector) ? [node] : node.querySelectorAll(targetSelector); | |
links.forEach(link => { | |
if (!link.dataset.settingsListener) { // Prevent multiple listeners | |
link.addEventListener('click', handleTrackDetailClick); | |
link.dataset.settingsListener = 'true'; | |
console.log("Added click listener for:", link.href); | |
} | |
}); | |
} | |
}); | |
} | |
} | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
} | |
observeTrackDetailLinks(); | |
} | |
/** | |
* Main initialization function. | |
*/ | |
function main() { | |
initializeOnPageLoad(); | |
initializeTrackDetailListeners(); | |
} | |
// Run the main function | |
main(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment