YouTube Music Bulk Unlike Tool

Bulk unlike all songs in YouTube Music liked songs playlist

  1. // ==UserScript==
  2. // @name YouTube Music Bulk Unlike Tool
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2
  5. // @description Bulk unlike all songs in YouTube Music liked songs playlist
  6. // @match https://music.youtube.com/playlist?list=LM
  7. // @grant none
  8. // ==/UserScript==
  9.  
  10. (function() {
  11. 'use strict';
  12.  
  13. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  14.  
  15. async function unlikeAllSongs() {
  16. let unlikedCount = 0;
  17. let failedCount = 0;
  18. let noProgressCount = 0;
  19. let lastHeight = 0;
  20.  
  21. updateStatus(`Starting process...`);
  22.  
  23. while (true) {
  24. const likeButtons = document.querySelectorAll('tp-yt-paper-icon-button.like[aria-pressed="true"]');
  25. let currentUnliked = 0;
  26.  
  27. for (let button of likeButtons) {
  28. try {
  29. button.scrollIntoView({ behavior: 'smooth', block: 'center' });
  30. await sleep(300);
  31. button.click();
  32. unlikedCount++;
  33. currentUnliked++;
  34. updateStatus(`Unliked: ${unlikedCount} | Failed: ${failedCount}`);
  35. await sleep(300);
  36. } catch (error) {
  37. console.error(`Failed to unlike a song: ${error}`);
  38. failedCount++;
  39. }
  40. }
  41.  
  42. if (currentUnliked === 0) {
  43. noProgressCount++;
  44. } else {
  45. noProgressCount = 0;
  46. }
  47.  
  48. const scrollContainer = document.querySelector('ytmusic-playlist-shelf-renderer');
  49. scrollContainer.scrollTop = scrollContainer.scrollHeight;
  50. await sleep(1000);
  51.  
  52. if (scrollContainer.scrollHeight === lastHeight) {
  53. noProgressCount++;
  54. }
  55. lastHeight = scrollContainer.scrollHeight;
  56.  
  57. if (noProgressCount > 10) {
  58. break;
  59. }
  60. }
  61.  
  62. updateStatus(`Completed! Unliked: ${unlikedCount} | Failed: ${failedCount}`);
  63. }
  64.  
  65. function createButton() {
  66. const button = document.createElement('button');
  67. button.textContent = 'Unlike All Songs';
  68. button.style.cssText = `
  69. position: fixed;
  70. top: 10px;
  71. right: 10px;
  72. z-index: 9999;
  73. padding: 10px 15px;
  74. background-color: #ff0000;
  75. color: white;
  76. border: none;
  77. border-radius: 5px;
  78. cursor: pointer;
  79. font-family: 'YouTube Sans', sans-serif;
  80. font-weight: bold;
  81. transition: background-color 0.3s;
  82. `;
  83. button.addEventListener('mouseover', () => button.style.backgroundColor = '#cc0000');
  84. button.addEventListener('mouseout', () => button.style.backgroundColor = '#ff0000');
  85. button.addEventListener('click', unlikeAllSongs);
  86. return button;
  87. }
  88.  
  89. function createStatusDisplay() {
  90. const display = document.createElement('div');
  91. display.id = 'unlike-status';
  92. display.style.cssText = `
  93. position: fixed;
  94. bottom: 10px;
  95. right: 10px;
  96. z-index: 9999;
  97. padding: 10px;
  98. background-color: rgba(0, 0, 0, 0.7);
  99. color: white;
  100. border-radius: 5px;
  101. font-family: 'YouTube Sans', sans-serif;
  102. font-size: 14px;
  103. `;
  104. return display;
  105. }
  106.  
  107. function updateStatus(message) {
  108. const display = document.getElementById('unlike-status') || createStatusDisplay();
  109. display.textContent = message;
  110. document.body.appendChild(display);
  111. }
  112.  
  113. document.body.appendChild(createButton());
  114. })();