|
const interval = 1; // wait time between chunks in seconds |
|
const chunkSize = 1; // number of songs to like at once |
|
|
|
// HTML elements selectors |
|
const contentsId = "contents"; |
|
const playlistName = "ytmusic-playlist-shelf-renderer"; |
|
const qryStr = "yt-button-shape[id='button-shape-like']"; |
|
|
|
const ytmLog = msg => console.log(`[YTM Liker] ${msg}`); |
|
|
|
const getSongs = (notLiked = true) => { |
|
const contents = document.getElementById(contentsId); |
|
const playlist = contents.getElementsByTagName(playlistName)[0]; |
|
const els = playlist.querySelectorAll( |
|
notLiked ? qryStr + "[aria-pressed='false']" : qryStr |
|
); |
|
return Array.from(els).map(el => el.getElementsByTagName("button")[0]); |
|
} |
|
|
|
const loadAllSongs = async () => { |
|
let lastCount = 0; |
|
|
|
while (true) { |
|
const songs = getSongs(false); |
|
const count = songs.length; |
|
ytmLog(`Loaded ${count} songs.`); |
|
|
|
if (count === lastCount) { |
|
break; |
|
} |
|
|
|
lastCount = count; |
|
songs[count - 1].scrollIntoView(); |
|
await sleep(1000); |
|
} |
|
} |
|
|
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); |
|
|
|
const likeAll = async () => { |
|
await loadAllSongs(); |
|
let songs = getSongs(); |
|
|
|
const total = songs.length; |
|
ytmLog(`Liking ${total} songs...`); |
|
|
|
for (let i = 0; i < total; i += chunkSize) { |
|
// scroll to the first song |
|
songs[i].scrollIntoView(); |
|
|
|
// click like buttons in chunks |
|
ytmLog(`Progress: ${i}/${total}.`); |
|
songs.slice(i, i + chunkSize).forEach(likeBtn => likeBtn.click()); |
|
|
|
// wait for the next chunk |
|
await sleep(interval * 1000); |
|
} |
|
|
|
ytmLog("All songs liked."); |
|
} |
|
|
|
likeAll(); |