Tự tạo web Copy Folder Google Drive

statistics
sG1HELm.png


Giới thiệu​

Google Drive là dịch vụ lưu trữ đám mây khá phổ biến, nhất là người Việt Nam. Thông thường, đa số những người mà tôi quen biết đều sử dụng Google Drive là nơi lưu trữ dữ liệu online của họ.

Tuy nhiên, có một vấn đề mà nhiều người dùng gặp khó khăn là copy folder của Google Drive. Google Drive không hỗ trợ trực tiếp, cho nên để sử dụng chức năng này, bạn cần phải sử dụng thông qua bên thứ ba. Một số người sẽ lo ngại khi sử dụng tool không phải của Google vì lý do bảo mật.

Và có một điều đặc biệt dành cho bạn khi đọc bài viết này, bạn sẽ đảm bảo được tài khoản google của bạn vẫn an toàn và chính bạn sẽ tự làm tool copy folder Google Drive luôn. Nghe vui nhỉ? Vậy thì bắt đầu thôi.

Dưới đây là một số công cụ cần để tạo tool này:

  • Google App Script.
  • Script.

Ưu điểm​

  • Có thể chạy trên DriveTeam.
  • Không copy những file đã có trong folder. Tiện trong trường hợp lỡ copy 750GB/ngày, thì mai quay lại copy tiếp 750GB nữa, không lo copy những file đã copy.
  • Tự làm, tự chơi. Yên tâm về bảo mật.

Nhược điểm​

  • App Script chỉ có thể chạy được 6 phút đối với account gmail và 30 phút đối với account google workspace.
  • Có file log hơi mất thẩm mỹ.

Thông tin​

Sau đó, các bạn copy đoạn code sau đây. Đoạn script này mình lấy từ labnol. Tuy nhiên, mình có về xào nấu lại cho dễ sử dụng hơn.
Nếu các bạn muốn tự tay làm bằng cách copy script thì nhớ bật Drive Activity API nha. Còn bạn muốn copy script gốc, làm sẵn không bị lỗi API thì bạn lướt xuống dưới nha.
JavaScript:
/*
License: GPLv3
Author: Lê Văn Đông
Refer: https://www.labnol.org/code/19979-copy-folders-drive
*/
function main(){
  let src = "https://drive.google.com/drive/folders/1_9nXZGdlGT9AktfWPa5JQIxcvgIzEYUG?usp=sharing";
  let des = "https://drive.google.com/drive/folders/0APgVE4H8erK0Uk9PVA";

  src = src.split("folders/")[1].split("?usp=sharing")[0];
  des = des.split("folders/")[1].split("?usp=sharing")[0];

  start(src, des);

}

function start(sourceFolderID, targetFolder) {
  //var sourceFolderID = "1_9nXZGdlGT9AktfWPa5JQIxcvgIzEYUG";
  //var targetFolder = "0ADWUkOWwzpYqUk9PVA";

  let folderID = DriveApp.getFolderById(sourceFolderID);
  let name = folderID.getName();

  var source = DriveApp.getFoldersByName(name);
  if(targetFolder == ""){
    console.log("Create folder" + name);
    targetFolder = "Copy of " + name;
    target = DriveApp.createFolder(targetFolder);
  }
  else{
    console.log("Go to target folder");
    target = DriveApp.getFolderById(targetFolder);
  }

  if (source.hasNext()) {
    copyFolder(source.next(), target);
  }
}

/*Get last time when folder changed
Input folder to get timestamp.
Return timestamp
=========================================================
*/
function getTimeChange(folder){
  let request = {
    "pageSize": 1,
    "ancestorName": ""
  }

  let value = "items/"+ folder.getId();
  request.ancestorName = value;
  let response = DriveActivity.Activity.query(request);
  let activities = response.activities;

  return new Date(activities[0].timestamp).getTime();
}

/*Read logs
Input folder.
Return timestamp
=========================================================
Find the file with the name is log.txt in this folder and read it.
If the result equals -1. This folder wasn't copied.
logs have a timestamp of the last activity source folder.
*/
function getTimeCopy(folder){
  let content = -1;
  let files = folder.getFilesByName("log");

  if (files.hasNext())
    content = Number(files.next().getBlob().getDataAsString());

  return content;
}

/*Write logs
Input:
  - timestamp - timestamp of source folder.
  - folder - folder to write
No return
=========================================================
Write to the file with name log.txt.
Default value is -1;
If this function is call, this folder copied.
Write timestamp of source folder.
*/
function writelog(timestamp,folder){

  files = folder.getFilesByName("log");

  if(files.hasNext()){
    file = files.next();
    file.setContent(timestamp);
  }
  else{
    folder.createFile("log",timestamp);
  }

}


function search(arr, x){
  let start=0
  let end=arr.length-1;

  while (start<=end){
    let mid = Math.floor((start+end)/2);

    if (arr[mid]==x)
      return true;
    else if (arr[mid]< x)
      start = mid + 1;
    else
      end = mid - 1;
  }
  return false;
}

function getAllNameOfFilesInFolder(folder){
  let arr = [];
  let files = folder.getFiles();
 
  while(files.hasNext()){
    let file = files.next();
    console.log("Scan file: " + file.getName());
    arr.push(file.getName());
    
  }
  arr.sort();
  return arr;
 
}

function getAllNameOfSubfolderInFolder(folder){
  let arr = [];
  let folders = folder.getFolders();
 
  while(folders.hasNext()){
    let folder = folders.next();
    console.log("Scan folder: " + folder.getName());
    arr.push(folder.getName());
  }
  arr.sort();
  return arr;
 
}

function copyFolder(source, target) {

  let folders = source.getFolders();
  let files   = source.getFiles();

  Logger.log("check out the changes...");
  let timesrc = getTimeChange(source);
  let timetarget = getTimeCopy(target);

  if(timesrc == timetarget){
    Logger.log("No changed");
    return; // Don't change. Don't Copy.
  }

  let list_file = getAllNameOfFilesInFolder(target);
  let list_folder = getAllNameOfSubfolderInFolder(target);

  while(files.hasNext()) {
    let file = files.next();
    if(search(list_file,file.getName()) ==false){
      console.log("Make copy file: " + file.getName());
      file.makeCopy(file.getName(), target);
    }
  }

  while(folders.hasNext()) {
    let subFolder = folders.next();
    let folderName = subFolder.getName();
    let check = search(list_folder,folderName);
    let targetFolder = "";
    if(check == false){
      console.log("Create subfolder: " + folderName);
      targetFolder = target.createFolder(folderName);
    }
    else{
      let x = target.getFoldersByName(folderName).next();
      x = x.getId();
      console.log("Go to subfolder: " + folderName);
      targetFolder = DriveApp.getFolderById(x);
    }

    copyFolder(subFolder, targetFolder);
    
  }
  Logger.log("Write log: " + source.getName());
  writelog(timesrc, target);
}

Hướng dẫn sử dụng​

Các bạn thay src thành URL folder nguồn. Còn des thành URL folder đích. Sau đó, bạn nhấn Run là thành công.

Lưu ý​

  • Bạn chỉ có thể copy tối đa 750 Gb/ngày.
  • Bạn cần truy cập link được share trước để tài khoản của bạn được cấp quyền truy cập thư mục thì mới copy được.

Link script và demo, hướng dẫn copy script​

Các bạn truy cập link Script version 2.0 để copy. Nếu không biết cách copy có thể xem video bên dưới.

Changelog​

Version 1.1​

Cho phép chọn thư mục đích để copy. Không copy những file đã có ở trong thư mục đích. => Chỉ copy những file chưa có thôi.

Cách sử dụng: Các bạn copy URL nguồn và URL đích. Script nó sẽ copy file từ thư mục nguồn vào thư mục đích. Những file đã có nó sẽ bỏ qua, không copy lại nữa. Nếu bạn bỏ trống link đích, nó sẽ tạo thư mục Copy of tại MyDrive.

Version 1.2​

  • Có log ở phần script.
  • Cải thiện tốc độ duyệt.
Bạn có thể copy script ở đây.

Version 2.0​

  • Cải thiện lớn về tốc độ duyệt file.
Bạn có thể copy script ở đây.
 
Sửa lần cuối:
Trả lời

statistics

Moderator
Thành viên BQT

Update:​

Version 1.1:​

Cho phép chọn thư mục đích để copy. Không copy những file đã có ở trong thư mục đích. => Chỉ copy những file chưa có thôi.

Cách sử dụng: Các bạn copy URL nguồn và URL đích. Script nó sẽ copy file từ thư mục nguồn vào thư mục đích. Những file đã có nó sẽ bỏ qua, không copy lại nữa. Nếu bạn bỏ trống link đích, nó sẽ tạo thư mục Copy of tại MyDrive. Bạn có thể truy cập tool tại đây.


Mã:
function doGet() {
  return HtmlService.createHtmlOutputFromFile('index');
}

function start(sourceFolderID, targetFolder) {
  //var sourceFolderID = "1_9nXZGEYUG";
  //var targetFolder = "1SUDWEtNSnrI3";

  var folderID = DriveApp.getFolderById(sourceFolderID);
  var name = folderID.getName();

  var source = DriveApp.getFoldersByName(name);
  if(targetFolder == ""){
    targetFolder = "Copy of " + name;
    target = DriveApp.createFolder(targetFolder);
  }
  else{
    target = DriveApp.getFolderById(targetFolder);
  }

  if (source.hasNext()) {
    copyFolder(source.next(), target);
  }
}

function checkExitsFiles(fileName, folder){
  var files = folder.getFiles();
  while(files.hasNext()){
    var file = files.next();
    if(file.getName() == fileName){
      return true;
    }
  }
  return false;
}

function checkExitsFolder(folderName, folder){
  var folders = folder.getFolders();
  while(folders.hasNext()){
    var folder = folders.next();
    if(folder.getName() == folderName){
      return folderName;
    }
  }
  return "";
}

function copyFolder(source, target) {

  var folders = source.getFolders();
  var files   = source.getFiles();

  while(files.hasNext()) {
    var file = files.next();
    if(!checkExitsFiles(file.getName(), target))
      file.makeCopy(file.getName(), target);
  }

  while(folders.hasNext()) {
    var subFolder = folders.next();
    var folderName = subFolder.getName();
    var check = checkExitsFolder(folderName, target);
    var targetFolder = "";
    if(check == ""){
      targetFolder = target.createFolder(folderName);
    }
    else{
      var x = target.getFoldersByName(check).next();
      x = x.getId();
      targetFolder = DriveApp.getFolderById(x);
    }

    copyFolder(subFolder, targetFolder);
  }

}

HTML:
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <h1>Copy Folder</h1>
    <label>Nhập link bạn muốn copy: </label><textarea id="srcURL"></textarea><br><br>
    <label>Link Folder đích: </label><textarea id="target" type="text"></textarea><br><br>
    <button id="btn">Run</button><br><br>
    
    <script>
      document.getElementById("btn").addEventListener("click", doStuff);

      function doStuff(){
        alert("Thành công! Đợi xíu nha má :)))");
        var srcURL = document.getElementById("srcURL").value;
        var src = srcURL.split("folders/")[1].split("?usp=sharing")[0];
        var tarURL = document.getElementById("target").value;
        var tar = tarURL.split("folders/")[1].split("?usp=sharing")[0];

        google.script.run.start(src,tar);
      }
    </script>

  </body>
</html>
 

statistics

Moderator
Thành viên BQT
Một cách khác là sử dụng trang này https://chrome.google.com/webstore/detail/copy-folder/kfbicpdhiofpicipfggljdhjokjblnhl
Điểm cộng so với tự làm :
+ Có log để xem tiến trình
+ Vì có log nên biết được đã copy đến giới hạn full drive hưa
+ Resume nếu copy lỗi, không run.
Khi nào rảnh, mình có thể sẽ làm thêm logs để tiện theo dõi. Còn Resume thì hiện tại v1.1 đã hoàn thành rồi đó bác.
 

statistics

Moderator
Thành viên BQT
Có bác nào test thử driveteam xem. Từ MyDrive -> DriveTeam và ngược lại.
DriveTeam A sang DriveTeam B và ngược lại. Theo dự đoán là chạy được.
Có bác nào chạy thử giúp mình nha


Chạy được trên DriveTeam
 
Sửa lần cuối:

Đông Phương

Rìu Chiến Bạc Chấm
có bác nào còn thừa acc GD Unlimited hay Edu gì đó không dùng thì có thể cho mình xin không? Mình muốn share ISO Windows/Office lên diễn đàn nhưng hiện tại các account của mình đã die hết rồi.
Xin cảm ơn.
 

statistics

Moderator
Thành viên BQT
Cám ơn bác nhiều ah. Hữu ích quá.

Bác cho em hỏi trang HTML do Google Apps Script tạo ra liệu có chèn được Mã tracking của Google Analytics không ah?
Em cũng mới nhờ làm được trang này nhưng không chèn được Mã tracking 😁
Bác thử dùng iframe xem, bác chèn mã tracking vào thẻ head.
Mã:
https://www.w3schools.com/tags/tag_iframe.ASP
Bác tạo trang trên github thử nha.

Chứ mình không sử dụng Analytics cho app script nên mình cũng không rõ lắm. Nhưng mình nghĩ là được đó.
 

advbiohazard

Gà con
có bác nào còn thừa acc GD Unlimited hay Edu gì đó không dùng thì có thể cho mình xin không? Mình muốn share ISO Windows/Office lên diễn đàn nhưng hiện tại các account của mình đã die hết rồi.
Xin cảm ơn.
Share để người ta die theo bác à:))))) ISO win với phần mềm các thứ gg drive nó quét cực gắt, cứ up lên là die sớm muộn
 

lehieu76

Búa Gỗ
Bác thử dùng iframe xem, bác chèn mã tracking vào thẻ head.
Mã:
https://www.w3schools.com/tags/tag_iframe.ASP
Bác tạo trang trên github thử nha.

Chứ mình không sử dụng Analytics cho app script nên mình cũng không rõ lắm. Nhưng mình nghĩ là được đó.
Cám ơn bác đã nhiệt tình hướng dẫn ah.
Lần đầu em biết có thể tạo web tĩnh trên Github :D mày mò 1 lúc cũng đặt được theo bác hướng dẫn
Nhưng em Google hình như thằng Google, Facebook không cho dùng iframe hoặc trỏ tên miền dạng frame ah.
Nếu rảnh thì bác xem giúp em có đúng không ạ
https://lehieu76.github.io/
1634573006583.png
 

statistics

Moderator
Thành viên BQT
Cám ơn bác đã nhiệt tình hướng dẫn ah.
Lần đầu em biết có thể tạo web tĩnh trên Github :D mày mò 1 lúc cũng đặt được theo bác hướng dẫn
Nhưng em Google hình như thằng Google, Facebook không cho dùng iframe hoặc trỏ tên miền dạng frame ah.
Nếu rảnh thì bác xem giúp em có đúng không ạ
https://lehieu76.github.io/
Xem phần đính kèm 28450
Bác sửa hàm doget lại tý xíu nha:
JavaScript:
function doGet(request) {
  return HtmlService.createTemplateFromFile('index').evaluate()
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

Chi tiết bác đọc bài này nha:
Mã:
https://www.bpwebs.com/embed-google-apps-script-web-apps-in-websites/

Mình test thử rồi, chạy ok nha bác. Bác tự chỉnh chiều cao chiều rộng cho phù hợp nhé.
Code demo:
HTML:
<!DOCTYPE html>
<html>
<body>

<h1>The iframe element</h1>

<iframe src="https://script.google.com/macros/s/AKfycbwR-B1cXD-MyGEDgeVDPTCSxU4uceMblif0OFWLMRcuQA649AWDWrq2S6OYI1fLYQm9/exec" " title=Hello">
</iframe>

</body>
</html>
 

Answer

Búa Gỗ
có bác nào còn thừa acc GD Unlimited hay Edu gì đó không dùng thì có thể cho mình xin không? Mình muốn share ISO Windows/Office lên diễn đàn nhưng hiện tại các account của mình đã die hết rồi.
Xin cảm ơn.
bạn thích thì inbox email của bạn mình tạo folder cho mà upload lên
 

lehieu76

Búa Gỗ
Bác sửa hàm doget lại tý xíu nha:
JavaScript:
function doGet(request) {
  return HtmlService.createTemplateFromFile('index').evaluate()
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

Chi tiết bác đọc bài này nha:
Mã:
https://www.bpwebs.com/embed-google-apps-script-web-apps-in-websites/

Mình test thử rồi, chạy ok nha bác. Bác tự chỉnh chiều cao chiều rộng cho phù hợp nhé.
Code demo:
HTML:
<!DOCTYPE html>
<html>
<body>

<h1>The iframe element</h1>

<iframe src="https://script.google.com/macros/s/AKfycbwR-B1cXD-MyGEDgeVDPTCSxU4uceMblif0OFWLMRcuQA649AWDWrq2S6OYI1fLYQm9/exec" " title=Hello">
</iframe>

</body>
</html>
cám ơn bác nhiều ah, may có bác chứ em dân không chuyên, mày mò mấy tuần nay :D
 

lehieu76

Búa Gỗ
Bác sửa hàm doget lại tý xíu nha:
JavaScript:
function doGet(request) {
  return HtmlService.createTemplateFromFile('index').evaluate()
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

Chi tiết bác đọc bài này nha:
Mã:
https://www.bpwebs.com/embed-google-apps-script-web-apps-in-websites/

Mình test thử rồi, chạy ok nha bác. Bác tự chỉnh chiều cao chiều rộng cho phù hợp nhé.
Code demo:
HTML:
<!DOCTYPE html>
<html>
<body>

<h1>The iframe element</h1>

<iframe src="https://script.google.com/macros/s/AKfycbwR-B1cXD-MyGEDgeVDPTCSxU4uceMblif0OFWLMRcuQA649AWDWrq2S6OYI1fLYQm9/exec" " title=Hello">
</iframe>

</body>
</html>
bác ơi, mình xin phép inbox bác nhờ bác tư vấn kỹ hơn nhé.