0

I have a google sheet with about 20 columns of data, all related to a video file. The video files are of plays from a football game. The video files are in google drive and named, m0001.mp4 to m0124.mp4 in order. Assuming for that game I have 124 video files (plays) for that game. For some games it might be m00356.mp4 to m00495.mp4 etc.

I did this before in excel using macros and gave in the name the first file and number of files and it would auto-popular with hyperlinks to the video files.

How can I do the same thing using scripts?

This was my macro from excel:

Sub nbsl()
Dim FldrLoc As String:  FldrLoc = "m:\2011 season\nbsl\"
    Dim rngAnchor As Range
    Dim CurrentFile As String:  CurrentFile = Dir(FldrLoc)
    Do While CurrentFile <> vbNullString
        Set rngAnchor = ActiveSheet.Range("V" & Rows.Count).End(xlUp).Offset(1, 0)
        ActiveSheet.Hyperlinks.Add Anchor:=rngAnchor, _
                            Address:=FldrLoc & CurrentFile, _
                            TextToDisplay:=CurrentFile
        CurrentFile = Dir()
    Loop
End Sub
prex
  • 719
  • 4
  • 17
  • Not sure what you are trying to do. Do you want to read a drive folder and put all file names + links in de sheet or do you have all information in the sheet and just want to add an hyperlink?Why would you use a macro for this in Google Sheets? Did you have a look at =HYPERLINK formula? A link to an video in drive is constructed like this: https://drive.google.com/file/d//preview – Niek Waarbroek Feb 05 '19 at 06:11
  • Welcome. Here's an alternative to Niek's excellent suggestion. First, familiarise yourself with accessing files on Drive. This should be useful [How to list all files in google drive in a folder with a set name?](https://stackoverflow.com/questions/36274928/). Second, create a loop where you increment the value of the file name, and create a hyperlink. This should be helpful [Search files in Google Drive and dynamic hyperlink to google sheet with google app script](https://stackoverflow.com/questions/53021347/). – Tedinoz Feb 05 '19 at 06:51
  • Niek, The reason I want to do this is the row will have about 20 columns of data of what is in the video file. It works the best if I enter 4 columns and 4 of my other coworkers enter 4 columns. We need to watch the video to pull the data for our columns. I want to add the hyperlinks first so we can click on them and get the data from the video. Once the data is enter we can sort on it and look for certain video clips. How can I create a script to auto populate those links? Thank you!!! – Jerome Learman Feb 07 '19 at 02:35
  • Tedinoz, Those are a big help. I need to spend a few hours on this I think but those might be the solution I am looking for. If they are, I will post my results here. Thank you!! – Jerome Learman Feb 07 '19 at 02:40
  • Well that sounds pretty positive. Just a note for the future, when you want to reply to someone (like Niek or myself above), start the name with an asterisk (@). This triggers an autocomplete feature, but it also puts the comment into the person's (Niek or myself) in-tray and we automatically get a notification of your comment. – Tedinoz Feb 11 '19 at 02:18
  • @Tedinoz I got a lot of it figured out, but I think there might be better ways to do it. I posted what I have figured out so far. Any suggestions? – Jerome Learman Mar 04 '19 at 05:30
  • @NiekWaarbroek I got a lot of it figured out, but I think there might be better ways to do it. I posted what I have figured out so far. Any suggestions? – Jerome Learman Mar 04 '19 at 05:30
  • @JeromeLearman Well done on your perseverance and research. I voted for your answer. There a mild sense of "supplementary questions" and StackOverflow doesn't really suit (or encourage) raising new topics in this way. Might I suggest you might edit your answer to move the _"things I haven't worked out"_, simplify them, and insert them **after** the code in a conversational tone as new challenges that came to light in the course of developing your answer and building your skills, and perhaps some might become new questions at some stage. – Tedinoz Mar 05 '19 at 22:26

3 Answers3

1

Thanks to @Tednioz & @Niek Waarbroek I was able to figure most of this out.

Below is my code.

function getFiles() {

  var dApp = DriveApp;
  var vfolder = dApp.getFoldersByName("video").next();
  var yearfolder = vfolder.getFoldersByName("2018").next();
  var gamefolder = yearfolder.getFoldersByName("game1").next();
  var folderez = gamefolder.getFoldersByName("ez").next();
  var foldersl = gamefolder.getFoldersByName("sl").next();
  var ezIter = folderez.getFiles();
  var slIter = foldersl.getFiles();
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(yearfolder+gamefolder);

  var i = 2;

  while (ezIter.hasNext()) {
    var file = ezIter.next();
    var name = file.getName();
    var url = file.getUrl();
    range = 'AC'+(i);
    ss.getRange(range).setValue(url);
    i++
}

  i = 2;
  while (slIter.hasNext()) {
    var file = slIter.next();
    var name = file.getName();
    var url = file.getUrl();
    range = 'AD'+(i);
    ss.getRange(range).setValue(url);
    i++
}
}

There are a few things that I have not been able to figure out 1) Is there a way use a files full path if you know it? Example: "Driveroot:\video\2018\game1\sl"

2) Is there a way to have the links show up as just the name to a file and not the full URL?

3) Is there a way to have the video automatically play and keep looking when you click on the hyperlink?

4) The files will be names dms0001, dms0002, ..... to say dms0189. That is not that order they are being loaded. Is there a way to do this?

  • _use a file's full path if you know it?..."_ That's something that should be explored in a new question. But I don't think that one can truly answer (or ask?) this without giving thought to the user interface. Hard-coding the year and game# is OK for development but not for a live system. An alternative might be to allow the user to select the year and game from dropdowns or checkboxes, and have the script then populate the output based on those choices. This would allow technical details such as Folder IDs to be hidden from view, but still used efficiently to deliver accurate output. – Tedinoz Mar 05 '19 at 22:28
  • `getFoldersByName` may be a problem because it returns **all the folders with a given name**. In the case of folders such as "game1", "ez" and "sl", you are likely to have multiple folders with these names. e.g. 2019/game1, 2018/game1; game1/ez, game2/ez, etc. So this command may not produce predictable results. I've proposed using `getFolderById(id)` which is reliable, though hardly user friendly. – Tedinoz Mar 05 '19 at 22:31
  • Displaying links rather than a url requires using `setFormula(formula)` [(ref)](https://developers.google.com/apps-script/reference/spreadsheet/range#setformulaformula) and the `HYPERLINK` formula. Add this to your loop `var formula = "=HYPERLINK(\""+url+"\",\""+name+"\")";` and `// Logger.log("DEBUG: The formula is: "+formula);//DEBUG`. And substitute `ss.getRange(range).setFormula(formula);` for your `setValue` command. Some comments in my answer here (https://stackoverflow.com/a/54757730/1330560) may be useful also. – Tedinoz Mar 05 '19 at 22:32
  • _Is there a way to have the video automatically play and keep looking when you click on the hyperlink?_ Again, a question for another time and place. The key is probably pre-sorting the names **before** they are output rather than after, as done presently. There's also the question of improving performance of the script so that the output is faster. – Tedinoz Mar 05 '19 at 22:34
  • _sorting file names_ Refer my alternative; I don't think it is perfect (it would be better to sort the names **before** they are output) but it is a start. The approach used in this topic (https://stackoverflow.com/a/36942674/1330560) is better and you could adapt it to your code. – Tedinoz Mar 05 '19 at 22:35
0

SORTING OF OUTPUT

This code is offered as a snippet to show how the results might be sorted in name order. The code, as written is in two parts; the first part sorts the results in column AC, before commencing the output for Column AD. This isn't strictly necessary and all the sorting could be combined


Sorting Column AC

  i++
  }
  // end of the first WHILE loop.

  // START OF THE SORTING CODE-Column AC
  // get the number of rows of content in Column AC
  var ACvals = ss.getRange("AC2:AC").getValues();
  var AClast = ACvals.filter(String).length;
  // Logger.log("DEBUG: AClast = "+AClast);  //DEBUG

  //  create a range
  var range = sheet.getRange(2, 29, AClast);
  // Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG

  // sort the range by file name
  range.sort({
    column: 29,
    ascending: true
  });

// END OF THE SORTING CODE-Column AC
i = 2;
// start of the second WHILE loop

Sorting Column AD

  i++
  }
  // end of the second WHILE loop. 
  // START OF THE SORTING CODE-Column AD
  // get the number of rows of content in Column AD
  var ADvals = ss.getRange("AD2:AD").getValues();
  var ADlast = ADvals.filter(String).length;
  // Logger.log("DEBUG: ADlast = "+ADlast);  //DEBUG

  //  create a range
  var range = sheet.getRange(2, 30, ADlast);
  // Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG

  // sort the range by file name
  range.sort({
    column: 30,
    ascending: true
  });
  // END OF THE SORTING CODE-Column AD
  }
Tedinoz
  • 5,911
  • 3
  • 25
  • 35
  • That worked if used var name = file.getName(); instead of creating my own like names. I have two solutions that worked. It doesn't look like I can use the full path name for folders, either use the method I am using or use the IDs. The only thing I'd like to be able to do is have the video auto play when I click on the link and loop. I'll start a new questions for that. Thank you for all of the help!!! – Jerome Learman Mar 07 '19 at 03:07
  • @JeromeLearman “have the video auto play when I click on the link and loop”. Just so I understand... do you mean the way that when you click a spreadsheet hyperlink, it then opens a separate modal link that you have to click to ‘open’ the link? – Tedinoz Mar 07 '19 at 06:54
  • @JeromeLearman Google "google sheets single click link"; there's a lot of info out there. Short story: can't be done in sheets; but long story, it can be done in a website, and there are topics that deal with publishing the script to the web. I really do think you need to look at the user interface as a whole - how the user is presented with options, how you deliver results based on their selections, and how/where the video output is displayed. I wouldn't be surprised if you concluded that a website gave the most effective solution. – Tedinoz Mar 07 '19 at 10:10
  • That is correct. To make a long story short each line in the google sheet related to a football play. I have 32 different columns of data to file in per play. The links are to links of the video of that play. Right now you click on the link it opens, you click play and you have to play again to play it again if you don't get all of the data from the field. This was in excel, and I'm switching to sheets to allow more users. I'm not opposed to a website, but I don't even know where to start with doing it on a website. Any suggestions? – Jerome Learman Mar 10 '19 at 12:09
  • I was hoping there was something I could add to the hyperlink that would start the video playing on open and something else to get it to loop. – Jerome Learman Mar 10 '19 at 12:11
0

I have two solutions that worked. I will post both below:

Option 1) Allows you to name the links something other than the file name:

function getFiles() {

  var dApp = DriveApp;
  var vfolder = dApp.getFoldersByName("video").next();
  var yearfolder = vfolder.getFoldersByName("2018").next();
  var gamefolder = yearfolder.getFoldersByName("game2").next();
  var folderez = gamefolder.getFoldersByName("ez").next();
  var foldersl = gamefolder.getFoldersByName("sl").next();
  var ezIter = folderez.getFiles();
  var slIter = foldersl.getFiles();
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(yearfolder+gamefolder);
  var i = 2;
  var files = [];

  while (ezIter.hasNext()) {
    files.push(ezIter.next());
} 

// sorts the files array by file names alphabetically
files = files.sort(function(a, b){
    var aName = a.getName().toUpperCase();
    var bName = b.getName().toUpperCase();

    return aName.localeCompare(bName);
});

files.forEach(function(file){
    var name = file.getName();
    var url = file.getUrl();
    range = 'AC'+(i);
    var filename = 'ezvideo'+(i-1);
    var semi = ";";  
    var hyp = "=hyperlink(\"";
    var quot = "\"";
    var clos = ")";
    var title = hyp  + url + quot + semi + quot + filename + quot + clos;  // str='=hyperlink("' + f.getUrl() + '","' + f.getName() + '")';
    ss.getRange(range).setValue(title);   
    i++;
});

  var i = 2;
  var files = [];
while (slIter.hasNext()) {
    files.push(slIter.next());
}

// sorts the files array by file names alphabetically
files = files.sort(function(a, b){
    var aName = a.getName().toUpperCase();
    var bName = b.getName().toUpperCase();

    return aName.localeCompare(bName);
});

files.forEach(function(file){
    var name = file.getName();
    var url = file.getUrl();
    range = 'AD'+(i);
    var filename = 'slvideo'+(i-1);
    var semi = ";";  
    var hyp = "=hyperlink(\"";
    var quot = "\"";
    var clos = ")";
    var title = hyp  + url + quot + semi + quot + filename + quot + clos;  // str='=hyperlink("' + f.getUrl() + '","' + f.getName() + '")';
    ss.getRange(range).setValue(title);   
    i++;
});
}

Or Option 2; which requires you to use the filenames to sort:

function getFiles() {

  var dApp = DriveApp;
  var vfolder = dApp.getFoldersByName("video").next();
  var yearfolder = vfolder.getFoldersByName("2018").next();
  var gamefolder = yearfolder.getFoldersByName("game1").next();
  var folderez = gamefolder.getFoldersByName("ez").next();
  var foldersl = gamefolder.getFoldersByName("sl").next();
  var ezIter = folderez.getFiles();
  var slIter = foldersl.getFiles();
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(yearfolder+gamefolder);

  var i = 2;

  while (ezIter.hasNext()) {
    var file = ezIter.next();
    var name = file.getName(); // use this or the created filename below
    var url = file.getUrl();
    range = 'AC'+(i);
    var filename = 'ezvideo'+(i-1);
    var semi = ";";  
    var hyp = "=hyperlink(\"";
    var quot = "\"";
    var clos = ")";
    var title = hyp  + url + quot + semi + quot + name + quot + clos;  // str='=hyperlink("' + f.getUrl() + '","' + f.getName() + '")';
    ss.getRange(range).setValue(title);   
    i++;
}

  // START OF THE SORTING CODE-Column AC
  // get the number of rows of content in Column AC
  var ACvals = ss.getRange("AC2:AC").getValues();
  var AClast = ACvals.filter(String).length;
  // Logger.log("DEBUG: AClast = "+AClast);  //DEBUG
  //  create a range
  var range = ss.getRange(2, 29, AClast);
  // Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG
  // sort the range by file name
  range.sort({
    column: 29,
    ascending: true
  });

// END OF THE SORTING CODE-Column AC  


  i = 2;
  while (slIter.hasNext()) {
    var file = slIter.next();
    var name = file.getName();
    var url = file.getUrl();
    range = 'AD'+(i);
    var filename = 'slvideo'+(i-1);
    var title = hyp  + url + quot + semi + quot + file + quot + clos;
    ss.getRange(range).setValue(title);  
    i++;
}

    // end of the second WHILE loop. 
  // START OF THE SORTING CODE-Column AD
  // get the number of rows of content in Column AD
  var ADvals = ss.getRange("AD2:AD").getValues();
  var ADlast = ADvals.filter(String).length;
  // Logger.log("DEBUG: ADlast = "+ADlast);  //DEBUG

  //  create a range
  var range = ss.getRange(2, 30, ADlast);
  // Logger.log("DEBUG: range = "+range.getA1Notation());//DEBUG

  // sort the range by file name
  range.sort({
    column: 30,
    ascending: true
  });
  // END OF THE SORTING CODE-Column AD
}

Thank you everyone for all of the help!!