gespinha
gespinha

Reputation: 8497

How to programatically select photos in a Google Photos album?

I'm trying to programatically select a photo from within a Google Photos Album in the browser, via the console.

I've tried the following:

const photo = document.getElementsByClassName('p137Zd')[0].parentElement

photo.querySelectorAll('div[role="checkbox"]').click()

But I'm getting an error. This quick code was meant to trigger a click() event and select the first photo in an album, but I'm getting an error saying:

Uncaught TypeError: photo.parentElement.querySelectorAll(...)[0].click is not a function

Can anyone help me achieve this?

Upvotes: 1

Views: 930

Answers (6)

shtse8
shtse8

Reputation: 1365

let t = 0
while (true) {
  let checkboxes = [...document.querySelectorAll('.ckGgle')].filter((x) => x.ariaChecked == 'false')
if (checkboxes.length > 0) {
    t = 0
  checkboxes.forEach((x) => x.click());
  document.getElementsByClassName("yDSiEe uGCjIb zcLWac eejsDc TWmIyd")[0].scrollBy(0, window.outerHeight);
} else {
    t++;
    if (t > 30) break
}
    await new Promise(resolve => setTimeout(resolve, 100));
}

try this script

Upvotes: 0

Todd
Todd

Reputation: 1

I was looking to download all my Google photos that contained images from 2016 to today. While the code from here helped, it was tedious to paste it over and over in the console. So below is the code on a loop with a timer to be copied nae pasted into the console. I added notes to help understand my thought process. (I'm sure it can be more efficient, but it works.)

////////////CHECKS ALL PHOTOS in google photos the EASY WAY////////////

let loopCount = 0;
let stopLoop = false;

function loopCheckboxes() { //This function is what checks for the non-selected photos
  document.querySelectorAll('div[role="checkbox"].QcpS9c.ckGgle:not([aria-label*="Select all"]):not([aria-checked="true"])').forEach(div => div.click());;
  for (i=0; i<allSelects.length; i++) {
    if (!allSelects[i].checked) {
      allSelects[i].click();
    }
  }
  loopCount++;
  if (loopCount < 500 && !stopLoop) { //Executes the loop 500 times
    setTimeout(loopCheckboxes, 500); //Executes one loop every half a second
  } else {
    console.log("Loop terminated"); //Terminates the loop after set amount of loops are done
  }
}

setTimeout(() => { //Timer function
  stopLoop = true;
  console.log("Timer expired, loop terminated"); //terminates the loops of the timer expires
}, 20000);//20 Second count

loopCheckboxes();

Upvotes: 0

Emre
Emre

Reputation: 1

If you zoom out, this code will select all visible content on the screen.

document.querySelectorAll('div[role="checkbox"].QcpS9c.ckGgle:not([aria-label*="Select all"]):not([aria-checked="true"])').forEach(div => div.click());

Upvotes: 0

Lajos Arpad
Lajos Arpad

Reputation: 76968

The problem is that querySelectorAll returns an array-like-object and it does not have a click() function. The items that are members of this array-like-object are elements and they all have individually a click function, but you cannot invoke it from the array-like-object (a NodeList, to be precise) that contains them.

In the accepted answer of @mplungjan, we see this approach

photo.querySelectorAll('div[role="checkbox"]').forEach(div => div.click());

which is correct.

But, you can also create a click function for a NodeList and then you would be able to run your initial code :)

NodeList.prototype.click = function() {
    for (let item of this) item.click();
};

document.querySelectorAll(".hd").forEach(item => item.parentNode.querySelectorAll("[type=button]").click());
<div>
    <input type="button" value="1" onclick="console.log(1)">
    <input type="button" value="2" onclick="console.log(2)">
    <input type="button" value="3" onclick="console.log(3)">
    <input type="hidden" class="hd">
</div>
<div>
    <input type="button" value="4" onclick="console.log(4)">
    <input type="button" value="5" onclick="console.log(5)">
    <input type="button" value="6" onclick="console.log(6)">
</div>
<div>
    <input type="button" value="7" onclick="console.log(7)">
    <input type="button" value="8" onclick="console.log(8)">
    <input type="button" value="9" onclick="console.log(9)">
    <input type="hidden" class="hd">
</div>

As we can see, once we define a click function for a NodeList that clicks all the elements inside, we can reuse it as many times as we would like.

So, while mplungjan's answer is correct and deserves to be accepted, I have decided to write a new answer about how we can add the feature that you missed here rather than working around it.

Upvotes: 0

HBIDamian
HBIDamian

Reputation: 1

As the other codes in this thread don't quite work from my experience, I've reused https://stackoverflow.com/a/73154187/22316590, to make it work for me.

document.querySelectorAll('div[role="checkbox"]:not([aria-label*="Select all"]):not([aria-checked="true"])').forEach(div => div.click());

I've added this :not([aria-label*="Select all"]), as I suspect that the Select All is also being clicked, which unselects the images. I've also added :not([aria-checked="true"]), so it doesn't uncheck images.

However, I've noticed that the images/checkboxes have to be rendered on the screen in order for it to work. So there's a lot of scrolling & repeating the command in console.

Upvotes: 0

mplungjan
mplungjan

Reputation: 178375

You get a collection from querySelectorAll so this could be a dupe

This is is simpler:

const photo = document.querySelector('.p137Zd').parentElement

In any case try

photo.querySelectorAll('div[role="checkbox"]').forEach(div => div.click());

Upvotes: 1

Related Questions