Search code examples
javascriptgoogle-apps-scriptiterator

Mistery of Iterators


I'm going crazy for the strange behaviour of the Iterators in Google Apps Script. My script picks a random folder (corresponding to a year between 2012 and the current year), then pick a random image in. The file's random criterion is a led by a random integer which stops the loop at the integer-th iteration. It works, the debug and the script silently execute. But, but, but: the photo-rolling rendering of the script deliveries always the same 4-5 pictures. They are thousands. I control the caching, also the F12 function tabs says the cache is null and Ctrl+F5 does not any positive effect. Then, I ask the script to log the URL of the image. Surprise: even if the random number that enters the if-statement is different, however the resulting URL is the same. By chance, the folder is the same, but the different random numbers get the same image picked. HELP! enter image description here

function doGet() {
  var folderImmagini_ID ="myID";
  //---
  // picking year folder between 2012 and current year
  var annoCorrente = new Date().getFullYear();
  var numFolderRandom = Math.random() * (annoCorrente - 2011) + 1;
  var nomeFolderRandom = (numFolderRandom + 2011).toString();
  var nomeFolderFinale = nomeFolderRandom.substring(0, nomeFolderRandom.indexOf("."));
  // once get random folder, picking a random image
  var foldersIterator = DriveApp.getFolderById(folderImmagini_ID).getFolders();
  var nomeCartella, cartella;
  while (foldersIterator.hasNext()) {
    cartella = foldersIterator.next(),
    nomeCartella = cartella.getName();
    if (nomeCartella == nomeFolderFinale) {
      var filesIterator = cartella.getFiles();
      var numeroFiles = 0, file;
      while (filesIterator.hasNext()) {
        numeroFiles = numeroFiles + 1;
        file = filesIterator.next();
      }
      var numFileRandom = Math.floor(Math.random() * numeroFiles) + 1;
      var ordineFile = 0;
      filesIterator = cartella.getFiles();
      while (filesIterator.hasNext()) {
        ordineFile = ordineFile + 1;
        if (ordineFile == numFileRandom) {
          var t = HtmlService.createTemplateFromFile('OutputHTML');
          var foto = filesIterator.next();
          t.fotoID = foto.getId();
                         Logger.log("nome folder: %s, numero random: %s, link foto: %s",nomeCartella, numFileRandom, 
                                    "https://drive.google.com/uc?export=download&id="+ t.fotoID);
          return t.evaluate();
        }
      }
    }   
  }
};
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Expires" content="0">
  </head>
  <body>
    <center><img src="https://drive.google.com/uc?export=download&id=<?= fotoID ?>" height="85%" width="85%"></center>
  </body>
</html>


Solution

  • Modification points:

    When I saw your showing script, it seems that var foto = filesIterator.next(); is used in the if-statement of if (ordineFile == numFileRandom) {,,,}. In this case, when ordineFile == numFileRandom is true, var foto = filesIterator.next(); is used for the first time. In this case, I'm worried that ordineFile = ordineFile + 1; is not used for selecting the file. I thought that this might be the reason for your current issue.

    If you want to modify your showing script, how about the following modification?

    From:

    while (filesIterator.hasNext()) {
      ordineFile = ordineFile + 1;
      if (ordineFile == numFileRandom) {
        var t = HtmlService.createTemplateFromFile('OutputHTML');
        var foto = filesIterator.next(); // <--- here
        t.fotoID = foto.getId();
        Logger.log("nome folder: %s, numero random: %s, link foto: %s", nomeCartella, numFileRandom,
          "https://drive.google.com/uc?export=download&id=" + t.fotoID);
        return t.evaluate();
      }
    }
    

    To:

    while (filesIterator.hasNext()) {
      ordineFile = ordineFile + 1;
      var foto = filesIterator.next(); // <--- here
      if (ordineFile == numFileRandom) {
        var t = HtmlService.createTemplateFromFile('OutputHTML');
        t.fotoID = foto.getId();
        Logger.log("nome folder: %s, numero random: %s, link foto: %s", nomeCartella, numFileRandom,
          "https://drive.google.com/uc?export=download&id=" + t.fotoID);
        return t.evaluate();
      }
    }
    
    • In this case, var foto = filesIterator.next(); was moved outside of the if-statement of if (ordineFile == numFileRandom) {,,,}.

    Note:

    • As another approach, I thought that the file is randomly selected from the file ID list. In this case, how about the following modification?

      function doGet() {
        var folderImmagini_ID = "myID";
        //---
        // picking year folder between 2012 and current year
        var annoCorrente = new Date().getFullYear();
        var numFolderRandom = Math.random() * (annoCorrente - 2011) + 1;
        var nomeFolderRandom = (numFolderRandom + 2011).toString();
        var nomeFolderFinale = nomeFolderRandom.substring(0, nomeFolderRandom.indexOf("."));
        // once get random folder, picking a random image
        var foldersIterator = DriveApp.getFolderById(folderImmagini_ID).getFolders();
        var nomeCartella, cartella;
      
        // I modified the below script.
        while (foldersIterator.hasNext()) {
          cartella = foldersIterator.next(), nomeCartella = cartella.getName();
          if (nomeCartella == nomeFolderFinale) {
            var filesIterator = cartella.getFiles();
            var fileIds = [];
            while (filesIterator.hasNext()) {
              fileIds.push(filesIterator.next().getId());
            }
            var numFileRandom = Math.floor(Math.random() * fileIds.length);
            var t = HtmlService.createTemplateFromFile('OutputHTML');
            t.fotoID = fileIds[numFileRandom];
            Logger.log("nome folder: %s, numero random: %s, link foto: %s", nomeCartella, numFileRandom + 1, "https://drive.google.com/uc?export=download&id=" + t.fotoID);
            return t.evaluate();
          }
        }
      }