简介

自动在线创建Google Drive谷歌团队无限储存网盘,独享管理员身份!

操作

获取授权

Rclone获取

我个人觉得不如第三方操作简单,点此可查看

  1. 安装依赖

    #CentOS系统
    yum install p7zip unzip -y
    #Debian/Ubuntu系统
    apt install -y p7zip-full
  2. 安装Rclone

    curl https://rclone.org/install.sh | bash
  3. 配置Rclone

    rclone config
  4. 参照下面内容选择输入命令
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
name> Rats  #配置名称,随便填
Type of storage to configure.
Enter a string value. Press Enter for the default ("").
Choose a number from below, or type in your own value
 1 / 1Fichier
   \ "fichier"
 2 / Alias for an existing remote
   \ "alias"
 3 / Amazon Drive
   \ "amazon cloud drive"
 4 / Amazon S3 Compliant Storage Provider (AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, etc)
   \ "s3"
 5 / Backblaze B2
   \ "b2"
 6 / Box
   \ "box"
 7 / Cache a remote
   \ "cache"
 8 / Dropbox
   \ "dropbox"
 9 / Encrypt/Decrypt a remote
   \ "crypt"
10 / FTP Connection
   \ "ftp"
11 / Google Cloud Storage (this is not Google Drive)
   \ "google cloud storage"
12 / Google Drive
   \ "drive"
13 / Google Photos
   \ "google photos"
14 / Hubic
   \ "hubic"
15 / JottaCloud
   \ "jottacloud"
16 / Koofr
   \ "koofr"
17 / Local Disk
   \ "local"
18 / Mega
   \ "mega"
19 / Microsoft Azure Blob Storage
   \ "azureblob"
20 / Microsoft OneDrive
   \ "onedrive"
21 / OpenDrive
   \ "opendrive"
22 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
   \ "swift"
23 / Pcloud
   \ "pcloud"
24 / Put.io
   \ "putio"
25 / QingCloud Object Storage
   \ "qingstor"
26 / SSH/SFTP Connection
   \ "sftp"
27 / Union merges the contents of several remotes
   \ "union"
28 / Webdav
   \ "webdav"
29 / Yandex Disk
   \ "yandex"
30 / http Connection
   \ "http"
31 / premiumize.me
   \ "premiumizeme"
Storage> 12  #选择12,Google Drive
client_id> 850428  #填上你的Google Drive客户端ID
client_secret> D72gPc  #填上你的Google Drive客户端密匙
Choose a number from below, or type in your own value
 1 / Full access all files, excluding Application Data Folder.
   \ "drive"
 2 / Read-only access to file metadata and file contents.
   \ "drive.readonly"
   / Access to files created by rclone only.
 3 | These are visible in the drive website.
   | File authorization is revoked when the user deauthorizes the app.
   \ "drive.file"
   / Allows read and write access to the Application Data folder.
 4 | This is not visible in the drive website.
   \ "drive.appfolder"
   / Allows read-only access to file metadata but
 5 | does not allow any access to read or download file content.
   \ "drive.metadata.readonly"
scope> 1 
ID of the root folder
Leave blank normally.
Fill in to access "Computers" folders. (see docs).
Enter a string value. Press Enter for the default ("").
root_folder_id> 
Service Account Credentials JSON file path 
Leave blank normally.
Needed only if you want use SA instead of interactive login.
Enter a string value. Press Enter for the default ("").
service_account_file> 
Edit advanced config? (y/n)
y) Yes
n) No
y/n> n  #输入n
Remote config
Use auto config?
 * Say Y if not sure
 * Say N if you are working on a remote or headless machine
y) Yes
n) No
y/n> n  #输入n
If your browser doesn't open automatically go to the following link: https://accounts.google.com/o/  #打开该地址获取code
Log in and authorize rclone for access
Enter verification code>hjdd   #输入你获取到的code
Configure this as a team drive?
y) Yes
n) No
y/n> n  #输入n
--------------------
[Rats]
type = drive
client_id = 85042871
client_secret = D72gPc
scope = drive
token = {"access_token":"y902Z"}  #记住里面的refresh_token参数
--------------------
y) Yes this is OK
e) Edit this remote
d) Delete this remote
y/e/d> y  #输入y
Current remotes:

Name                 Type
====                 ====
Rats                 drive

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q  #输入q保存退出

执行 rclone config file 查看 rclone.conf 路径。找到 root_folder_idrefresh_token 记录下来。

第三方获取

  1. 访问 https://install.gd.workers.dev/
  2. 点击“获取认证码”,授权 Google 账户 (推荐无限盘)
  3. 将新窗口获取到的代码,复制粘贴到“Auth认证码(通过认证连接获取认证码)”处

  4. 点击“生成代码”,稍等
  5. 下拉页面,查看生成后的代码,记录 client_idclient_secretrefresh_token

关于Google Drive目录ID
打开团队盘(或文件夹或别人共享的文件夹),看地址栏。
https://drive.google.com/drive/folders/{这后面就是目录id}
留空是根目录。

配置

  1. 注册 CloudFlare Workers
  2. 复制 Workers代码 ,并将 client_idclient_secretrefresh_token 修改为自己的

点击查看代码

var authConfig = {
  version: "1.0.1-fix1",
  dailyLimit: true, // 是否限制每一个邮箱每天只能提交一次请求
  client_id: "",
  client_secret: "",
  refresh_token: "", // 授权 token
  domain: "", // 面页中显示本站团队盘域, 可不填
  // 黑名单, 免费版没有数据库, 一个可行思路是从自己服务器上获取, 可自行实现
  black_list: ["example@gmail.com"]
};

var gd;

var today;

var html = `
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"
    />
    <title>创建Google TeamDrive</title>
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
    />
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
      integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
      integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
      crossorigin="anonymous"
    ></script>
  <!--源码地址: https://github.com/yyuueexxiinngg/some-scripts/blob/master/workers/google/drive/create-share-teamdrive.js-->
  </head>
  <body>
    <div id="app">
      <div id="container" class="container">
        <div class="row">
          <div class="col-sm-8 offset-sm-2 col-md-6 offset-md-3 text-center">
            <h1>创建Google TeamDrive</h1>
             <p>${authConfig.version}</p>
         ${
           authConfig.domain
             ? ` <h5>本站团队盘域为:  ${authConfig.domain}</h5>`
             : ""
         }
            <p>
              后端多个API请求, 过程耗时较长, 请耐心等待,
              <span style="color: red"><b>切勿重复提交</b></span>
            </p>
            <br />
            <div class="info-form text-left">
              <form id="teamDriveForm">
                <div class="form-group">
                  <label for="teamDriveName" class="sr-only">
                    TeamDrive 名称
                  </label>
                  <input
                    type="text"
                    class="form-control"
                    id="teamDriveName"
                    placeholder="TeamDrive 名称"
                  />
                </div>
                <div class="form-group">
                  <label for="emailAddress" class="sr-only">
                    您的GMail邮箱地址
                  </label>
                  <input
                    type="email"
                    class="form-control"
                    id="emailAddress"
                    placeholder="您的GMail邮箱地址"
                  />
                </div>
                <div class="form-check">
                  <input
                    type="checkbox"
                    class="form-check-input"
                    id="customTheme"
                    value=""
                  />
                  <label class="form-check-label" for="customTheme">
                    自定TeamDrive主题头图
                  </label>
                </div>
                <div id="customThemeSection" class="d-none">
                  <div id="teamDriveThemePreview"></div>
                  <div id="teamDriveThemeOptions">
                    <div class="form-check">
                      <input
                        class="form-check-input"
                        type="radio"
                        name="teamDriveTheme"
                        id="teamDriveThemeOptionRandom"
                        value="random"
                        checked
                      />
                      <label
                        class="form-check-label"
                        for="teamDriveThemeOptionRandom"
                      >
                        随机
                      </label>
                    </div>
                  </div>
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
              </form>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div
      class="modal fade"
      id="loadMe"
      tabindex="-1"
      role="dialog"
      aria-labelledby="loadMeLabel"
    >
      <div class="modal-dialog modal-sm" role="document">
        <div class="modal-content">
          <div class="modal-body text-center">
            <div class="d-flex justify-content-center">
              <div class="spinner-border" role="status">
                <span class="sr-only">正在创建中...</span>
              </div>
            </div>
            <div clas="loader-txt">
              <p>正在创建中...</p>
            </div>
          </div>
        </div>
      </div>
    </div>
    <footer class="page-footer font-small blue">
      <div class="footer-copyright text-center py-3">
        © 2020 源码:
        <a
          href="https://github.com/yyuueexxiinngg/some-scripts/blob/master/workers/google/drive/create-share-teamdrive.js"
        >
          yyuueexxiinngg
        </a>
        <br />
        Special Thanks:
        <a href="https://github.com/donwa/goindex">
          donwa
        </a>
      </div>
    </footer>
  </body>
  <script>
    var teamDriveThemes;
    $("input[id=customTheme]").change(function() {
      if ($(this).is(":checked")) {
        $("#customThemeSection").removeClass("d-none");
      } else {
        $("#customThemeSection").addClass("d-none");
        $("input[name=teamDriveTheme]")[0].click();
      }
    });
    $.get("/teamDriveThemes", function(json) {
      teamDriveThemes = json.teamDriveThemes;
      $.each(json.teamDriveThemes, function(i, item) {
        $("#teamDriveThemeOptions").append(\`
        <div class="form-check">
           <input
            class="form-check-input"
            type="radio"
            name="teamDriveTheme"
            id="teamDriveThemeOption-\${item.id}"
            value="\${item.id}"
          />
          <label class="form-check-label" for="teamDriveThemeOption-\${item.id}">
           \${item.id}
          </label>
        </div>
        \`);
      });
      $("input[name=teamDriveTheme]").change(function() {
        var themeId = this.value;
        if (themeId === "random") {
          $("#teamDriveThemePreview").html("");
        } else {
          var theme = teamDriveThemes.find(function(t) {
            return t.id == themeId;
          });
          $("#teamDriveThemePreview").html(
            \`
          <div class="card" style="background-color: \${theme.colorRgb}">
            <img src="\${theme.backgroundImageLink}" class="card-img-top" alt="\${theme.id}" />
            <div class="card-body">
              <h5 class="card-text" style="color: white">
                \${theme.id}
              </h5>
            </div>
          </div>
      \`
          );
        }
      });
      $("#teamDriveForm").on("submit", function(event) {
        event.preventDefault();
        $("#loadMe").modal({
          backdrop: "static", //remove ability to close modal with click
          keyboard: false, //remove option to close with keyboard
          show: true //Display loader!
        });
        $.ajax({
          type: "POST",
          url: "/drive",
          data: JSON.stringify({
            teamDriveName: $("input[id=teamDriveName]").val(),
            teamDriveThemeId: $("input[name=teamDriveTheme]:checked").val(),
            emailAddress: $("input[id=emailAddress]").val()
          }),
          success: function(data) {
            $("#loadMe").modal("hide");
            alert("成功!");
          },
          error: function(request, status, error) {
            $("#loadMe").modal("hide");
            alert("失败!" + request.responseText);
          },
          contentType: "application/json"
        });
      });
    });
  </script>
  <style type="text/css">
    .card-img-top {
      width: 100%;
      object-fit: cover;
    }
  </style>
</html>
`;

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});

var dailyLimit = [];

/**
 * Fetch and log a request
 * @param {Request} request
 */
async function handleRequest(request) {
  if (authConfig.dailyLimit) {
    if (!today) today = new Date().getDate();

    // Remove email rate limit every day
    if (new Date().getDate() != today) {
      today = new Date().getDate();
      dailyLimit.length = 0;
    }
  }

  if (gd == undefined) {
    gd = new googleDrive(authConfig);
  }
  let url = new URL(request.url);
  let path = url.pathname;

  switch (path) {
    case "/teamDriveThemes":
      let teamDriveThemes = await gd.getTeamDriveThemes();
      return new Response(JSON.stringify(teamDriveThemes), {
        status: 200,
        headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*"
        }
      });
    case "/drive":
      if (request.method === "POST") {
        const requestBody = await request.json();

        if (authConfig.dailyLimit) {
          if (dailyLimit.includes(requestBody.emailAddress)) {
            return new Response("每天只允许提交一次", {
              status: 429
            });
          } else {
            dailyLimit.push(requestBody.emailAddress);
          }
        }

        if (authConfig.black_list.includes(requestBody.emailAddress)) {
          return new Response("Failed", {
            status: 429
          });
        }

        try {
          let result = await gd.createAndShareTeamDrive(requestBody);
          return new Response("OK", {
            status: 200
          });
        } catch (err) {
          return new Response(err.toString(), {
            status: 500
          });
        }
      } else if (request.method === "OPTIONS") {
        return new Response("", {
          status: 200,
          headers: {
            "Access-Control-Allow-Origin": "*"
          }
        });
      } else {
        return new Response("Bad Request", {
          status: 400
        });
      }
    default:
      return new Response(html, {
        status: 200,
        headers: {
          "Content-Type": "text/html; charset=utf-8",
          "Access-Control-Allow-Origin": "*"
        }
      });
  }
}
// https://stackoverflow.com/a/2117523
function uuidv4() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
    // tslint:disable-next-line:one-variable-per-declaration
    const r = (Math.random() * 16) | 0,
      // tslint:disable-next-line:triple-equals
      v = c == "x" ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
}

class googleDrive {
  constructor(authConfig) {
    this.authConfig = authConfig;
    this.accessToken();
  }

  async getTeamDriveThemes() {
    let url = "https://www.googleapis.com/drive/v3/about";
    let requestOption = await this.requestOption();
    let params = { fields: "teamDriveThemes" };
    url += "?" + this.enQuery(params);
    let response = await fetch(url, requestOption);
    return await response.json();
  }

  async createAndShareTeamDrive(requestBody) {
    // Create team drive
    console.log("Creating TeamDrive");
    let url = "https://www.googleapis.com/drive/v3/drives";
    let requestOption = await this.requestOption(
      { "Content-Type": "application/json" },
      "POST"
    );
    let params = { requestId: uuidv4() };
    url += "?" + this.enQuery(params);
    let post_data = {
      name: requestBody.teamDriveName
    };
    if (
      requestBody.teamDriveThemeId &&
      requestBody.teamDriveThemeId !== "random"
    ) {
      post_data.themeId = requestBody.teamDriveThemeId;
    }
    requestOption.body = JSON.stringify(post_data);
    let response = await fetch(url, requestOption);
    let result = await response.json();
    const teamDriveId = result.id;
    console.log("Created TeamDrive ID", teamDriveId);

    // Get created drive user permission ID
    console.log(`Getting creator permission ID`);
    url = `https://www.googleapis.com/drive/v3/files/${teamDriveId}/permissions`;
    params = { supportsAllDrives: true };
    params.fields = "permissions(id,emailAddress)";
    url += "?" + this.enQuery(params);
    requestOption = await this.requestOption();
    response = await fetch(url, requestOption);
    result = await response.json();
    const currentUserPermissionID = result.permissions[0].id;
    console.log(currentUserPermissionID);

    // Share team drive with email address
    console.log(`Sharing the team drive to ${requestBody.emailAddress}`);
    url = `https://www.googleapis.com/drive/v3/files/${teamDriveId}/permissions`;
    params = { supportsAllDrives: true };
    url += "?" + this.enQuery(params);
    requestOption = await this.requestOption(
      { "Content-Type": "application/json" },
      "POST"
    );
    post_data = {
      role: "organizer",
      type: "user",
      emailAddress: requestBody.emailAddress
    };
    requestOption.body = JSON.stringify(post_data);
    response = await fetch(url, requestOption);
    await response.json();

    // Delete creator from the team drive
    console.log("Deleting creator from the team drive");
    url = `https://www.googleapis.com/drive/v3/files/${teamDriveId}/permissions/${currentUserPermissionID}`;
    params = { supportsAllDrives: true };
    url += "?" + this.enQuery(params);
    requestOption = await this.requestOption({}, "DELETE");
    response = await fetch(url, requestOption);
    return await response.text();
  }

  async accessToken() {
    console.log("accessToken");
    if (
      this.authConfig.expires == undefined ||
      this.authConfig.expires < Date.now()
    ) {
      const obj = await this.fetchAccessToken();
      if (obj.access_token != undefined) {
        this.authConfig.accessToken = obj.access_token;
        this.authConfig.expires = Date.now() + 3500 * 1000;
      }
    }
    return this.authConfig.accessToken;
  }

  async fetchAccessToken() {
    console.log("fetchAccessToken");
    const url = "https://www.googleapis.com/oauth2/v4/token";
    const headers = {
      "Content-Type": "application/x-www-form-urlencoded"
    };
    const post_data = {
      client_id: this.authConfig.client_id,
      client_secret: this.authConfig.client_secret,
      refresh_token: this.authConfig.refresh_token,
      grant_type: "refresh_token"
    };

    let requestOption = {
      method: "POST",
      headers: headers,
      body: this.enQuery(post_data)
    };

    const response = await fetch(url, requestOption);
    return await response.json();
  }

  async requestOption(headers = {}, method = "GET") {
    const accessToken = await this.accessToken();
    headers["authorization"] = "Bearer " + accessToken;
    return { method: method, headers: headers };
  }

  enQuery(data) {
    const ret = [];
    for (let d in data) {
      ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
    }
    return ret.join("&");
  }
}

将修改后的代码粘贴到 CloudFlare 部署。

绑域名

  1. 先让需要绑定的域名通过cf,指向ip随意。
  2. 添加Route

测试

做了一个测试站:https://curly-field-dc43.ensucc0214.workers.dev/
有兴趣的,可以试试。

其他
英国谢菲尔德大学:
https://gdrive.zppcw.cn/

404 NOT FOUND:
https://gd.404edu.workers.dev/

https://gd.zxd.workers.dev/

http://leon.educationhost.cloud/

swccd.edu团队盘:https://teamdrive.xcpx.workers.dev/

洛杉矶加利福尼亚大学团队盘:https://ucla.ur.workers.dev/

日本国際大学团队盘:
https://iuj.ur.workers.dev/

自动创建:
https://www.teamdrive.workers.dev





参考整理自:ensu's bloggoindexyyuueexxiinnggWONGCW 網誌rclone


Last modification:February 14, 2020
如果觉得我的文章对你有用,欢迎打赏!