Skip to content

Instantly share code, notes, and snippets.

@avipars
Last active March 5, 2025 00:11
Show Gist options
  • Save avipars/02f74c158b6f79567343bb655acce695 to your computer and use it in GitHub Desktop.
Save avipars/02f74c158b6f79567343bb655acce695 to your computer and use it in GitHub Desktop.
Script to download all your Kindle books (run before before Feb 26, 2025)
// Updated by AmCan Tech: https://medium.com/avi-parshan-studios/you-will-no-longer-be-able-to-download-ebooks-from-amazon-c3a81deb6928
// 0. Optional - have chrome save all your downloads to a specific folder without asking you each time (via chrome settings)
// 1. Log in to your Amazon account
// 2. Go to your Content Library > Books - https://www.amazon.com/hz/mycd/digital-console/contentlist/booksAll/dateDsc/
// 3. Go to page 1
// 4. Run the script in the dev console and wait a few seconds for it to start
(async function () {
// Close the notification if it appears
function closeNotification() {
const notifClose = document.querySelector("span#notification-close");
if (notifClose) {
notifClose.click();
}
}
// Change to whatever device you want to select. 1 = first device, 2 = second device, etc
const DEVICE = 1;
const GO_TO_NEXT = true; // whether to proceed to next page, set to false if you do not want to continue after current page
// Pause for a given duration (in milliseconds)
function pause(duration = 1000) {
return new Promise((resolve) => setTimeout(resolve, duration));
}
await pause(5000);
const allPages = Array.from(document.querySelectorAll("a.page-item"));
const lastPage = allPages[allPages.length - 1];
const lastPageNumber = parseInt(lastPage.innerText, 10);
let currentPage = document.querySelector("a.page-item.active");
let currentPageNumber = parseInt(currentPage.innerText, 10);
do {
await pause(5000);
currentPage = document.querySelector("a.page-item.active");
currentPageNumber = parseInt(currentPage.innerText, 10);
console.log(`Downloading page ${currentPageNumber} of ${lastPageNumber}`);
// Select all buttons that open the "Download & transfer via USB" dialog.
// They removed the id, so we have to use the class name now
// It's a bit more brittle but it should do.
const menus = Array.from(
document.querySelectorAll(
'div[class*="Dropdown-module_dropdown_container"]'
)
)
.map((container) => Array.from(container.children).find((child) => child.innerHTML.indexOf("DOWNLOAD_AND_TRANSFER_DIALOG") !== -1))
.filter((item) => !!item);
for (let menu of menus) {
// Extract the ASIN from the menu's id.
// E.g. "DOWNLOAD_AND_TRANSFER_ACTION_B07HYK662L" -> "B07HYK662L"
const dialog = menu.querySelector(`div[id^='DOWNLOAD_AND_TRANSFER_DIALOG_']`)
if (!dialog) {
console.warn(`No dialog found for menu`);
continue;
}
const parts = dialog.id.split("_");
const asin = parts[parts.length - 1];
console.log(`Processing book with ASIN: ${asin}`);
// Click the menu to open the dialog
menu.click();
await pause(500);
// Within the dialog, select the first radio button (device) to download.
// This selector targets the list for this ASIN.
const inputSelector = `ul#download_and_transfer_list_${asin} li[class^='ActionList-module_action_list_item__'] > div > label`;
const inputList = Array.from(menu.querySelectorAll(inputSelector));
console.log(inputList.length);
if (!inputList) {
console.warn(`No download option found for ASIN ${asin}`);
continue;
}
const deviceToCheck = inputList.length >= DEVICE ? DEVICE - 1 : 0;
const input = inputList[deviceToCheck];
if (!input) {
console.log(`No download option found for ASIN ${asin}`);
continue;
}
input.click();
await pause(500);
// Find the confirm button within the dialog for this ASIN.
const buttonSelector = `div[id^='DOWNLOAD_AND_TRANSFER_DIALOG_${asin}'] div[class^='DeviceDialogBox-module_button_container__'] > div[id$='_CONFIRM']`;
const button = document.querySelector(buttonSelector);
if (!button) {
console.warn(`No confirm button found for ASIN ${asin}`);
continue;
}
button.click();
await pause(1000);
closeNotification();
await pause(500);
}
if (currentPage) {
const nextPage = currentPage.nextElementSibling;
if (nextPage && GO_TO_NEXT) {
console.log('Moving to next page');
nextPage.click();
}
}
} while (currentPageNumber < lastPageNumber && GO_TO_NEXT); //stop after end of all pages or if variable set to false
})();
// original: https://gist.github.com/lfhbento/3388607475edc23a571e8eaf568469e3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment