forked from mrishab/google-photos-delete-tool
-
Notifications
You must be signed in to change notification settings - Fork 11
/
delete_photos.js
112 lines (94 loc) · 3.36 KB
/
delete_photos.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
(async function() {
const CONFIG = {
maxCount: 10000,
selectors: {
counter: ".rtExYb",
checkbox: ".ckGgle[aria-checked=false]",
photoDiv: ".yDSiEe.uGCjIb.zcLWac.eejsDc.TWmIyd",
deleteButton: 'button[aria-label="Delete"]',
confirmationButton: ".VfPpkd-T0kwCb button.VfPpkd-LgbsSe.VfPpkd-LgbsSe-OWXEXe-k8QpJ.nCP5yc.AjY5Oe.LQeN7.kDryjd"
},
timeout: 600000,
scrollDelay: 300
};
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const waitUntil = async (condition, timeout = CONFIG.timeout) => {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const result = await condition();
if (result) return result;
await wait(CONFIG.scrollDelay);
}
throw new Error("Timeout reached");
};
const getElement = (selector) => document.querySelector(selector);
const getElements = (selector) => [...document.querySelectorAll(selector)];
const getCount = () => {
const counterElement = getElement(CONFIG.selectors.counter);
return counterElement ? parseInt(counterElement.textContent, 10) || 0 : 0;
};
const scrollPhotoList = async () => {
const photoDiv = getElement(CONFIG.selectors.photoDiv);
const initialTop = photoDiv.scrollTop;
await waitUntil(() => {
photoDiv.scrollBy(0, photoDiv.clientHeight);
return photoDiv.scrollTop > initialTop;
});
};
const scrollPhotoListTo = (top = 0) => {
getElement(CONFIG.selectors.photoDiv).scrollTop = top;
};
const scrollPhotoListBy = async (height = 0) => {
const photoDiv = getElement(CONFIG.selectors.photoDiv);
await waitUntil(() => {
const initialTop = photoDiv.scrollTop;
photoDiv.scrollBy(0, height);
return waitUntil(() => getElement(CONFIG.selectors.checkbox), 500)
.catch(() => null);
});
};
const deleteSelected = async () => {
const count = getCount();
if (count <= 0) return;
console.log(`Deleting ${count} photos`);
getElement(CONFIG.selectors.deleteButton).click();
const confirmationButton = await waitUntil(() =>
getElement(CONFIG.selectors.confirmationButton)
);
confirmationButton.click();
await waitUntil(() => getCount() === 0);
scrollPhotoListTo(0);
};
const selectPhotos = async () => {
const checkboxes = await waitUntil(() => {
const elements = getElements(CONFIG.selectors.checkbox);
return elements.length > 0 ? elements : null;
});
const currentCount = getCount();
const targetCheckboxes = checkboxes.slice(0, CONFIG.maxCount - currentCount);
targetCheckboxes.forEach(checkbox => checkbox.click());
await wait(200);
const newCount = getCount();
console.log(`Selected ${newCount} photos`);
return { newCount, lastCheckbox: targetCheckboxes[targetCheckboxes.length - 1] };
};
async function deleteGooglePhotos() {
try {
while (true) {
const { newCount, lastCheckbox } = await selectPhotos();
if (newCount >= CONFIG.maxCount) {
await deleteSelected();
} else {
const { top } = lastCheckbox.getBoundingClientRect();
await scrollPhotoListBy(top);
}
}
} catch (error) {
console.error("An error occurred:", error);
} finally {
await deleteSelected();
console.log("End of deletion process");
}
}
await deleteGooglePhotos();
})();