-
-
Save lfhbento/3388607475edc23a571e8eaf568469e3 to your computer and use it in GitHub Desktop.
// ==UserScript== | |
// @name Kindle Download | |
// @namespace http://tampermonkey.net/ | |
// @version 2025-02-20 | |
// @description Download all your kindle books | |
// @author You | |
// @match https://www.amazon.com/hz/mycd/digital-console/contentlist/booksPurchases/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=amazon.com | |
// @grant none | |
// ==/UserScript== | |
// 1. Log in to your Amazon account | |
// 2. Go to your Content Library > Books - https://www.amazon.com/hz/mycd/digital-console/contentlist/booksPurchases/dateDsc/ | |
(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; | |
// 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 = lastPage ? parseInt(lastPage.innerText, 10) : 1; | |
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}`); | |
// 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(); | |
const menuItem = Array.from(menu.childNodes).find((node) => node.querySelector(`div[id^='DOWNLOAD_AND_TRANSFER_DIALOG_']`)); | |
menuItem.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) { | |
nextPage.click(); | |
} | |
} | |
} while (currentPageNumber < lastPageNumber); | |
})(); |
Great script, thanks! I have more than 1000 books, so I needed some automation to go to the next page. Find my fork of your script here: https://gist.github.com/JohanKlos/3a92f6a55b8f1a8e712ce3c4b1510dd3
This script worked perfectly to download my collections. I was able to open each collection and click the Start Downloads Button and it worked!
FYI...It does a continuous loop on the last page. On the aged system used it takes about 1 min 30 secs per page. I calculated the time to return to click the Stop Downloads button. Then moved to the next category to start again.
Thank you very much for sharing this to help others!
I have it going, but my collection is so large it stops after page 399. My library is 43,492 so 1740 pages, but Amazon only shows 400 pages. I've downloaded the first 400 pages of A-Z, and last of A-Z. A-Z authors first 400 and last 400. I'll do most recent and oldest purchases. I'm afraid I'll be missing some books. Any suggestions? I plan on doing individual categories for collections, but have 1,461 not in a collections so I'm afraid I'll be missing some books. Is there a way for it to continue?
Reverse the sort sequence and it starts back with page 1 now being the first one you bought. Copy the link from the browser page then paste it into the @Move line and save. Go to the browser page and refresh. I had 2 machines going from both directions.
On an older machine with slow (5Mb/s) hotspot, it sometimes fails to download all, but I went back on the few it missed.
Too bad this script doesn't have a hard limit of say, 2 downloads at a time as an option.
What is the code so I dont have to restart each page? I am not good at this and I am using TamperMonkey. I have 400+ pages/ Probably around 487. I have changed the code..... or think I have but still only doing 25 at a time and I am on Page 87
Thanks for everything you did @lfhbento. I managed to download all 15339 purchased books in my kindle library! I'm done.
I have it going, but my collection is so large it stops after page 399. My library is 43,492 so 1740 pages, but Amazon only shows 400 pages. I've downloaded the first 400 pages of A-Z, and last of A-Z. A-Z authors first 400 and last 400. I'll do most recent and oldest purchases. I'm afraid I'll be missing some books. Any suggestions? I plan on doing individual categories for collections, but have 1,461 not in a collections so I'm afraid I'll be missing some books. Is there a way for it to continue?
Reverse the sort sequence and it starts back with page 1 now being the first one you bought. Copy the link from the browser page then paste it into the @Move line and save. Go to the browser page and refresh. I had 2 machines going from both directions.
And I thought I had a large library! You definitely have me beat. I was able to get all mine through the method you used above. I never could get the script to run past page 400.
Just wanted to say "Thank you" @lfhbento.
The script worked great (when Amazon didn't screw up). The change for device in the list was also much appreciated.
Worked perfectly, thanks!
Thank you so much @lfhbento. Ran it from the browser console and it worked brilliantly.
@lfhbento missed your brilliant assist. Since I started learning how to be a python prompt engineer, I wonder if I can get my books by using the browser accessible https://read.amazon.com/kindle-library? What do you think?
Amazon: You're making it really hard to justify being honest. Also, it's not sailing the 7 seas, to use my preferred reader software.
Ugh, only found this out tonight. :(