Skip to content

Instantly share code, notes, and snippets.

@nmccready
Last active December 5, 2025 18:56
Show Gist options
  • Select an option

  • Save nmccready/96d8dedc993c43c6aaa297e48e9d116f to your computer and use it in GitHub Desktop.

Select an option

Save nmccready/96d8dedc993c43c6aaa297e48e9d116f to your computer and use it in GitHub Desktop.
Youtube Music Uploads Bulk Albumn Delete
/*
<ytmusic-two-row-item-renderer class="style-scope ytmusic-grid-renderer" is-web-delhi-icons-enabled="" aspect-ratio="MUSIC_TWO_ROW_ITEM_THUMBNAIL_ASPECT_RATIO_SQUARE"><!--css-build:shady--><!--css_build_scope:ytmusic-two-row-item-renderer--><!--css_build_styles:video.youtube.src.web.polymer.shared.ui.styles.yt_base.styles.css.js,video.youtube.src.web.polymer.music.app.ui.shared.styles.ytmusic_base_styles.ytmusic.base.styles.css.js,video.youtube.src.web.polymer.music.app.ui.ytmusic_two_row_item_renderer.ytmusic.two.row.item.renderer.css.js-->
<a class="yt-simple-endpoint image-wrapper style-scope ytmusic-two-row-item-renderer" tabindex="-1" title="'74 Jailbreak" href="browse/FEmusic_library_privately_owned_release_detailb_po_CILri8az3JW6RBIMNzQgamFpbGJyZWFrGgVhYyBkYyIDZ3Bt">
<ytmusic-thumbnail-renderer class="image style-scope ytmusic-two-row-item-renderer" thumbnail-crop="MUSIC_THUMBNAIL_CROP_UNSPECIFIED"><!--css-build:shady--><!--css-build:shady--><yt-img-shadow id="image" class="image style-scope ytmusic-thumbnail-renderer no-transition" object-fit="COVER" style="background-color: transparent;" loaded=""><!--css-build:shady--><!--css-build:shady--><img id="img" draggable="false" class="style-scope yt-img-shadow" alt="" width="226" src="https://i9.ytimg.com/vi_locker/JMViTRf0RUc/locker.png?sqp=-oaymwEICOIBEOIBIAA&amp;rs=AMzJL3lYoMZpvm4Mo7HMdrL9o-ckx0Whsg"></yt-img-shadow>
</ytmusic-thumbnail-renderer>
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
<tp-yt-paper-ripple id="ripple" class="ripple style-scope ytmusic-two-row-item-renderer" noink=""><!--css-build:shady--><!--css-build:shady--><div id="background" class="style-scope tp-yt-paper-ripple"></div>
<div id="waves" class="style-scope tp-yt-paper-ripple"></div>
</tp-yt-paper-ripple>
<ytmusic-item-thumbnail-overlay-renderer class="thumbnail-overlay style-scope ytmusic-two-row-item-renderer" is-web-delhi-icons-enabled="" content-position="MUSIC_ITEM_THUMBNAIL_OVERLAY_CONTENT_POSITION_BOTTOM_RIGHT" display-style="MUSIC_ITEM_THUMBNAIL_OVERLAY_DISPLAY_STYLE_HOVER" play-button-state="default" animate-transitions=""><!--css-build:shady--><!--css-build:shady--><ytmusic-background-overlay-renderer id="background" class="style-scope ytmusic-item-thumbnail-overlay-renderer" style="--ytmusic-background-overlay-background: linear-gradient(rgba(0,0,0,0.502),rgba(0,0,0,0.000),rgba(0,0,0,0.000));"><!--css-build:shady--><!--css-build:shady--></ytmusic-background-overlay-renderer>
<div id="content" class="style-scope ytmusic-item-thumbnail-overlay-renderer">
<ytmusic-play-button-renderer id="play-button" class="style-scope ytmusic-item-thumbnail-overlay-renderer" role="button" tabindex="0" animated="" state="default" is-web-delhi-icons-enabled="" self-position="MUSIC_ITEM_THUMBNAIL_OVERLAY_CONTENT_POSITION_BOTTOM_RIGHT" aria-label="Play '74 Jailbreak" icon="PLAY_ARROW" size="MUSIC_PLAY_BUTTON_SIZE_MEDIUM" elevation="1" aria-disabled="false" style="--ytmusic-play-button-icon-color: rgba(255,255,255,1.000); --ytmusic-play-button-icon-loading-color: rgba(255,255,255,0.302); --ytmusic-play-button-background-color: rgba(0,0,0,0.600); --ytmusic-play-button-active-background-color: rgba(0,0,0,1.000); --ytmusic-play-button-loading-indicator-color: rgba(225,0,45,0.000); --ytmusic-play-button-active-scale-factor: 1.2;"><!--css-build:shady--><!--css-build:shady--><div class="content-wrapper style-scope ytmusic-play-button-renderer">
<dom-if class="style-scope ytmusic-play-button-renderer"><template is="dom-if"></template></dom-if>
<yt-icon class="icon style-scope ytmusic-play-button-renderer"><!--css-build:shady--><!--css-build:shady--><span class="yt-icon-shape style-scope yt-icon ytSpecIconShapeHost"><div style="width: 100%; height: 100%; display: block; fill: currentcolor;"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" aria-hidden="true" style="pointer-events: none; display: inherit; width: 100%; height: 100%;"><path d="M5 4.623V19.38a1.5 1.5 0 002.26 1.29L22 12 7.26 3.33A1.5 1.5 0 005 4.623Z"></path></svg></div></span></yt-icon>
<dom-if class="style-scope ytmusic-play-button-renderer"><template is="dom-if"></template></dom-if>
<tp-yt-paper-spinner-lite class="loading-indicator style-scope ytmusic-play-button-renderer" hidden="" aria-hidden="true" aria-label="loading"><!--css-build:shady--><!--css-build:shady--><div id="spinnerContainer" class=" style-scope tp-yt-paper-spinner-lite">
<div class="spinner-layer style-scope tp-yt-paper-spinner-lite">
<div class="circle-clipper left style-scope tp-yt-paper-spinner-lite">
<div class="circle style-scope tp-yt-paper-spinner-lite"></div>
</div>
<div class="circle-clipper right style-scope tp-yt-paper-spinner-lite">
<div class="circle style-scope tp-yt-paper-spinner-lite"></div>
</div>
</div>
</div>
</tp-yt-paper-spinner-lite>
</div>
</ytmusic-play-button-renderer>
<dom-if class="style-scope ytmusic-item-thumbnail-overlay-renderer"><template is="dom-if"></template></dom-if>
</div>
<ytmusic-menu-renderer class="menu style-scope ytmusic-two-row-item-renderer" slot="menu" aria-haspopup="menu" dropdown-only=""><!--css-build:shady--><!--css-build:shady--><div id="top-level-buttons" class="style-scope ytmusic-menu-renderer">
<dom-repeat as="button" class="style-scope ytmusic-menu-renderer"><template is="dom-repeat"></template></dom-repeat>
</div>
<yt-button-shape id="button-shape" class="style-scope ytmusic-menu-renderer">
<button class="yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button yt-spec-button-shape-next--enable-backdrop-filter-experiment" title="" aria-label="Action menu"><div aria-hidden="true" class="yt-spec-button-shape-next__icon"><span class="ytIconWrapperHost" style="width: 24px; height: 24px;"><span class="yt-icon-shape ytSpecIconShapeHost"><div style="width: 100%; height: 100%; display: block; fill: currentcolor;"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" aria-hidden="true" style="pointer-events: none; display: inherit; width: 100%; height: 100%;"><path d="M12 4a2 2 0 100 4 2 2 0 000-4Zm0 6a2 2 0 100 4 2 2 0 000-4Zm0 6a2 2 0 100 4 2 2 0 000-4Z"></path></svg></div></span></span></div><yt-touch-feedback-shape aria-hidden="true" class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"><div class="yt-spec-touch-feedback-shape__stroke"></div><div class="yt-spec-touch-feedback-shape__fill"></div></yt-touch-feedback-shape></button></yt-button-shape>
<dom-if class="style-scope ytmusic-menu-renderer"><template is="dom-if"></template></dom-if>
</ytmusic-menu-renderer>
</ytmusic-item-thumbnail-overlay-renderer>
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
<div id="thumbnail-corner-overlay" class="style-scope ytmusic-two-row-item-renderer">
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
</div>
<dom-repeat class="style-scope ytmusic-two-row-item-renderer"><template is="dom-repeat"></template></dom-repeat>
</a>
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
<div class="details style-scope ytmusic-two-row-item-renderer">
<div class="title-group style-scope ytmusic-two-row-item-renderer">
<dom-if class="style-scope ytmusic-two-row-item-renderer"><template is="dom-if"></template></dom-if>
<yt-formatted-string class="title style-scope ytmusic-two-row-item-renderer" tabindex="-1" has-link-only_=""><a class="yt-simple-endpoint style-scope yt-formatted-string" spellcheck="false" href="browse/FEmusic_library_privately_owned_release_detailb_po_CILri8az3JW6RBIMNzQgamFpbGJyZWFrGgVhYyBkYyIDZ3Bt" dir="auto">'74 Jailbreak</a></yt-formatted-string>
</div>
<span class="substring-group style-scope ytmusic-two-row-item-renderer">
<span id="inline-badges" class="style-scope ytmusic-two-row-item-renderer"></span>
<yt-formatted-string class="subtitle style-scope ytmusic-two-row-item-renderer" respect-html-dir="" tabindex="-1"><span class="style-scope yt-formatted-string">Album</span><span class="style-scope yt-formatted-string"> • </span><a class="yt-simple-endpoint style-scope yt-formatted-string" spellcheck="false" href="browse/FEmusic_library_privately_owned_artist_detaila_po_CILri8az3JW6RBIFYWMgZGM">AC/DC</a><span class="style-scope yt-formatted-string"> • </span><span class="style-scope yt-formatted-string">2003</span></yt-formatted-string>
</span>
<yt-formatted-string class="third-title style-scope ytmusic-two-row-item-renderer" ellipsis-truncate="" respect-html-dir="" tabindex="-1" is-empty="" ellipsis-truncate-styling="" title=""><!--css-build:shady--><!--css-build:shady--><yt-attributed-string class="style-scope yt-formatted-string"></yt-attributed-string></yt-formatted-string>
</div>
<div id="footer-button" class="style-scope ytmusic-two-row-item-renderer"></div>
</ytmusic-two-row-item-renderer>
*/
let albumns = document.body.querySelectorAll('ytmusic-two-row-item-renderer.style-scope.ytmusic-grid-renderer');
let doLog = false;
(async () => {
for (const album of albumns) {
// Force hover state by adding a CSS class
album.classList.add('hovered');
let mouseOverEvent = new MouseEvent('mouseover', { bubbles: true, cancelable: true });
album.dispatchEvent(mouseOverEvent);
// Click the album's menu button
const menuRenderer = album.querySelector('ytmusic-menu-renderer.menu.ytmusic-two-row-item-renderer');
if (menuRenderer) {
const menuButton = menuRenderer.querySelector('button.yt-spec-button-shape-next');
if (doLog) console.log({ menuButton });
if (menuButton) {
if (doLog) console.log('Clicking menu button for album:', album);
menuButton.click();
await new Promise(resolve => setTimeout(resolve, 500)); // Wait for the menu to open
// HTML structure of the "Delete album" option for reference ( KEEP DO NOT DLELETE)
/*
<ytmusic-menu-navigation-item-renderer class="style-scope ytmusic-menu-popup-renderer" role="menuitem" tabindex="-1" is-web-delhi-icons-enabled="" aria-disabled="false" aria-selected="false"><!--css-build:shady--><!--css-build:shady-->
<a id="navigation-endpoint" class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer" tabindex="-1" href="#">
<yt-icon class="icon style-scope ytmusic-menu-navigation-item-renderer" aria-hidden=""><!--css-build:shady--><!--css-build:shady--><span class="yt-icon-shape style-scope yt-icon ytSpecIconShapeHost"><div style="width: 100%; height: 100%; display: block; fill: currentcolor;"><svg xmlns="http://www.w3.org/2000/svg" height="18" viewBox="0 0 18 18" width="18" focusable="false" aria-hidden="true" style="pointer-events: none; display: inherit; width: 100%; height: 100%;"><path d="M14.25 2.25h-3V1.5a.75.75 0 00-.75-.75h-3a.75.75 0 00-.75.75v.75h-3a1.5 1.5 0 00-1.5 1.5h13.5a1.5 1.5 0 00-1.5-1.5Zm-9.75 12v-9H3v9a3 3 0 003 3h6a3 3 0 003-3v-9h-1.5v9a1.5 1.5 0 01-1.5 1.5H6a1.5 1.5 0 01-1.5-1.5ZM7.5 6a.75.75 0 00-.75.75v6a.75.75 0 101.5 0v-6A.75.75 0 007.5 6Zm3 0a.75.75 0 00-.75.75v6a.75.75 0 101.5 0v-6A.75.75 0 0010.5 6Z"></path></svg></div></span></yt-icon>
<yt-formatted-string class="text style-scope ytmusic-menu-navigation-item-renderer">Delete album</yt-formatted-string>
</a>
</ytmusic-menu-navigation-item-renderer>
*/
// Fix the query selector for the "Delete album" option
// const deleteOption = document.querySelector(
const deleteOption = Array.from(
document.querySelectorAll(
'ytmusic-menu-navigation-item-renderer.style-scope.ytmusic-menu-popup-renderer > a > yt-formatted-string.text.style-scope.ytmusic-menu-navigation-item-renderer'
)
).find(option => option.textContent.trim() === 'Delete album');
if (doLog) console.log({ deleteOption });
if (deleteOption && deleteOption.textContent.includes('Delete album')) {
if (doLog) console.log('Clicking delete option for album:', album);
deleteOption.click();
await new Promise(resolve => setTimeout(resolve, 500)); // Wait for the confirmation dialog
// CONFIRMATION DIALOG FOR REFRENCE ( KEEP DO NOT DELETE)
/*
<yt-button-renderer
id="confirm-button" class="style-scope yt-confirm-dialog-renderer" button-renderer=""
button-next=""
dialog-confirm="">
<yt-button-shape>
<button class="yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--overlay yt-spec-button-shape-next--size-m yt-spec-button-shape-next--enable-backdrop-filter-experiment"
title="" aria-label="Delete" aria-disabled="false">
<div class="yt-spec-button-shape-next__button-text-content">
<span class="yt-core-attributed-string yt-core-attributed-string--white-space-no-wrap" role="text">
Delete
</span>
</div>
<yt-touch-feedback-shape aria-hidden="true" class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--overlay-touch-response">
<div class="yt-spec-touch-feedback-shape__stroke">
</div><div class="yt-spec-touch-feedback-shape__fill"></div></yt-touch-feedback-shape></button>
</yt-button-shape>
<tp-yt-paper-tooltip offset="8" disable-upgrade=""></tp-yt-paper-tooltip>
</yt-button-renderer>
*/
// Confirm the deletion in the dialog
const deleteButton = document.querySelector(
'button.yt-spec-button-shape-next[aria-label="Delete"]'
);
if (doLog) console.log({ deleteButton });
if (deleteButton) {
deleteButton.click();
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait for the deletion to complete
}
}
}
}
// Remove the forced hover state
album.classList.remove('hovered');
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment