Greasy Fork

Plex web album and artist name swap

Swaps the album and artist names so the album name is on top

目前为 2024-02-09 提交的版本。查看 最新版本

// ==UserScript==
// @name         Plex web album and artist name swap
// @namespace    http://tampermonkey.net/
// @version      2024-02-08
// @description  Swaps the album and artist names so the album name is on top
// @author       frondonson
// @license      MIT

// @match        https://app.plex.tv/desktop/*


// @icon         https://www.google.com/s2/favicons?sz=64&domain=plex.tv
// @grant        none
// ==/UserScript==
(async function start()
{
	//wait for library to load
	await waitForElm('.DirectoryListPageContent-pageContentScroller-O3oHlt').then(element => {
		setTimeout(startLibrary, 50);
	});
	
	//wait for Recomended to load
	await waitForElm('.DirectoryHubsPageContent-pageContentScroller-jceJrG').then(element => {
		setTimeout(startRecomended, 50);
	});
})();

function startLibrary()
{
	//Direct parrent of album [data-testid="cellItem"] divs
	let allAlbumsParent = document.querySelector('div.DirectoryListPageContent-pageContentScroller-O3oHlt>div');

	console.log(allAlbumsParent);
	
	//Set up mutation observer
	var config = { attributes: false, childList: true, subtree: false };
	var observer = new MutationObserver(handleLibraryMutations);

	observer.observe(allAlbumsParent, config);
	
	//Do first batch of albums from page load
	let firstLoadAlbumDivs = allAlbumsParent.querySelectorAll('div[data-testid="cellItem"]');
	doSwaps(firstLoadAlbumDivs);
}

function handleLibraryMutations(mutations)
{
	let newAlbumDivs = mutations[0].target.children;
	
	doSwaps(newAlbumDivs);
}

function startRecomended()
{
	//Direct parrent of album [data-testid="cellItem"] divs
	let allRecomendedParent = document.querySelector('div.DirectoryHubsPageContent-pageContentScroller-jceJrG>div');

	console.log(allRecomendedParent);
	
	//Set up mutation observer, subtree true becase albums are spread out in several parent divs
	var config = { attributes: false, childList: true, subtree: true };
	
	var observer = new MutationObserver(handleRecomendedMutations);

	observer.observe(allRecomendedParent, config);
	
	//Do first batch of albums from page load
	let firstLoadAlbumDivs = allRecomendedParent.querySelectorAll('div[data-testid="cellItem"]');
	doSwaps(firstLoadAlbumDivs);
}
function handleRecomendedMutations(mutations)
{
	let newAlbumDivs = mutations[0].target.querySelectorAll('div[data-testid="cellItem"]');
	
	doSwaps(newAlbumDivs);
}

function doSwaps(nodeList)
{
	//parrent.children is a HTMLcollection not a nodeList, use iterable for each
	//https://stackoverflow.com/questions/35969974/foreach-is-not-a-function-error-with-javascript-array
	for (const albumDiv of nodeList) 
	{
		if(albumDiv.childElementCount < 3 || albumDiv.lastChild.nodeName == ('SPAN'))
		{ continue; }
		if(albumDiv.classList.contains('SwapAlbumNameUserScript-swapped'))
		{ continue; }
		
		let artistNode = albumDiv.children[1];
		//Classlist- MetadataPosterCardTitle-centeredSingleLineTitle-EuZHlc MetadataPosterCardTitle-singleLineTitle-lPd1B2 MetadataPosterCardTitle-title-ImAmGu Link-default-bdWb1S Link-isHrefLink-nk7Aiq
		let albumNode = albumDiv.children[2];
		//Classlist- MetadataPosterCardTitle-centeredSingleLineTitle-EuZHlc MetadataPosterCardTitle-singleLineTitle-lPd1B2 MetadataPosterCardTitle-title-ImAmGu MetadataPosterCardTitle-isSecondary-gGuBpd Link-default-bdWb1S Link-isHrefLink-nk7Aiq
		
		artistNode.classList.add('MetadataPosterCardTitle-isSecondary-gGuBpd');
		albumNode.classList.remove('MetadataPosterCardTitle-isSecondary-gGuBpd');
		
		//Swap positions - (x, y) insert node X before node Y
		albumDiv.insertBefore(albumNode, artistNode);
		
		albumDiv.classList.add('SwapAlbumNameUserScript-swapped');
	}
	
}

//https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists
function waitForElm(selector) {
    return new Promise(resolve => {
        if (document.querySelector(selector)) {
            return resolve(document.querySelector(selector));
        }

        const observer = new MutationObserver(mutations => {
            if (document.querySelector(selector)) {
                observer.disconnect();
                resolve(document.querySelector(selector));
            }
        });

        // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    });
}