// Get necessary data from the WIZ_global_data window object const sid = window.WIZ_global_data.FdrFJe const bl = window.WIZ_global_data.cfb2h const at = encodeURIComponent(window.WIZ_global_data.SNlM0e) // Get document language and generate random request ID const hl = document.documentElement.lang const reqid = Math.round((Math.random() * 100000) + 300000) // Define the RPC IDs for subscriptions and feed (endpoints for batchexecute calls) const rpcids = { "subscriptions": "Saeaed", "feed": "ncqJEe", } // Define the options for the fetch requests const fetchOptions = body => { return { "headers": { "accept": "*/*", "cache-control": "no-cache", "content-type": "application/x-www-form-urlencoded;charset=UTF-8", "pragma": "no-cache", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "sec-gpc": "1", "x-same-domain": "1" }, "referrer": "https://podcasts.google.com/", "referrerPolicy": "origin", "body": body, "method": "POST", "mode": "cors", "credentials": "include" } } // Array to store all played episodes const allPlayedEpisodes = [] // Function to get all podcast IDs from the subscriptions async function getAllPodcastIds() { try { // Fetch data from the "subscriptions" endpoint const response = await fetch(`https://podcasts.google.com/_/PodcastsUi/data/batchexecute?rpcids=${rpcids.subscriptions}&source-path=%2Fsubscriptions&f.sid=${sid}&bl=${bl}&hl=${hl}&_reqid=${reqid}`, fetchOptions(`f.req=%5B%5B%5B%22${rpcids.subscriptions}%22%2C%22%5B%5D%22%2Cnull%2C%223%22%5D%5D%5D&at=${at}&`)); const data = await response.text(); // Parse the response data to get the individual podcast IDs const subscriptionsRaw = JSON.parse(JSON.parse(data.replace(")]}'", "").trim())[0][2])[0] const allPodcastIds = [] subscriptionsRaw.forEach((subscription) => { const podcastId = subscription[10] allPodcastIds.push(podcastId) }); // Return the array of podcast IDs return allPodcastIds } catch (err) { console.log(err); } } // Function to get played episodes for a given podcast ID async function getEpisodesPlayed(podcastId) { try { // Fetch data from the "feed" endpoint const response = await fetch(`https://podcasts.google.com/_/PodcastsUi/data/batchexecute?rpcids=${rpcids.feed}&source-path=%2Ffeed%2F${podcastId}&f.sid=${sid}&bl=${bl}&hl=${hl}&_reqid=${reqid + 1000}`, fetchOptions(`f.req=%5B%5B%5B%22${rpcids.feed}%22%2C%22%5B%5C%22${podcastId}%5C%22%5D%22%2Cnull%2C%221%22%5D%5D%5D&at=${at}&`)); const data = await response.text(); // Parse the response data to get the individual episodes const episodesRaw = JSON.parse(JSON.parse(data.replace(")]}'", "").trim())[0][2])[1][0]; const episodesPlayed = []; episodesRaw.forEach((episode) => { // Ignore unplayed episodes if (null != episode[3]) { const podcastName = episode[1]; const episodeName = episode[8]; // Generate row of data containing podcast name, date, episode name and progress const episodeData = [ podcastName.includes(',') ? `"${podcastName}"` : podcastName, new Date(episode[11] * 1000).toISOString().split('T')[0], episodeName.includes(',') ? `"${episodeName}"` : episodeName, episode[3] > 0.95 ? "✅" : Math.round(episode[3] * 100).toString() + "%" ]; episodesPlayed.push(episodeData); } }); // Return the array of played episodes for the podcast return episodesPlayed; } catch (err) { console.log(err); } } // Function to log all played episodes and generate the CSV file async function logAllPlayedEpisodes() { // Get all podcast IDs const allMyIds = await getAllPodcastIds(); // Get played episodes for each podcast ID const allPlayedEpisodes = (await Promise.all(allMyIds.map(async podcastId => { const playedEpisodesInThisPodcast = await getEpisodesPlayed(podcastId); return playedEpisodesInThisPodcast; }))).flatMap(episodes => episodes); // Sort the played episodes: first ASC by podcast name and then DESC by date allPlayedEpisodes.sort((a, b) => { const podcastComparison = a[0].toLowerCase().localeCompare(b[0].toLowerCase()); if (podcastComparison !== 0) { return podcastComparison; } return b[1].localeCompare(a[1]); }); // Generate the CSV content let csvContent = "podcast,date,episode,played\n" + allPlayedEpisodes.map(episode => episode.join(",")).join("\n"); // Download the CSV file const csvBlob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const csvUrl = URL.createObjectURL(csvBlob); const link = document.createElement('a'); link.setAttribute('href', csvUrl); link.setAttribute('download', 'google_podcasts_listening_history.csv'); link.click(); } // Call the function to log all played episodes and generate the CSV file logAllPlayedEpisodes()