From 6a63ea8e85b8c3b25ec07ad78e48dff478c11651 Mon Sep 17 00:00:00 2001
From: Aicirou <2643053021@qq.com>
Date: Wed, 20 May 2020 02:11:53 +0800
Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3v2.0.0=E5=85=AC=E6=B5=8B?=
=?UTF-8?q?=E7=89=88=E5=A4=A7=E5=AE=B6=E5=8F=8D=E9=A6=88=E7=9A=84=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
go2index/index.js | 1487 +++++++++++-----------
package-lock.json | 2 +-
public/index.html | 19 +-
src/utils/AcrouUtil.js | 152 ++-
src/views/common/BreadCrumb.vue | 7 +
src/views/common/Navbar.vue | 13 +-
src/views/page/GoList.vue | 63 +-
src/views/page/components/list/index.vue | 9 +-
8 files changed, 932 insertions(+), 820 deletions(-)
diff --git a/go2index/index.js b/go2index/index.js
index 5127c2f..19a2d9f 100644
--- a/go2index/index.js
+++ b/go2index/index.js
@@ -1,91 +1,98 @@
var authConfig = {
- "siteName": "Achirou's Cloud", // 网站名称
- "version" : "1.1.0", // 程序版本
- "theme" : "acrou",
- /*"client_id": "202264815644.apps.googleusercontent.com",
+ siteName: "Achirou's Cloud", // 网站名称
+ version: "1.1.0", // 程序版本
+ theme: "acrou",
+ /*"client_id": "202264815644.apps.googleusercontent.com",
"client_secret": "X4Z3ca8xfWDb1Voo-F9a7ZxJ",*/
- // 强烈推荐使用自己的 client_id 和 client_secret
- "client_id": "",
- "client_secret": "",
- "refresh_token": "", // 授权 token
- /**
- * 设置要显示的多个云端硬盘;按格式添加多个
- * [id]: 可以是 团队盘id、子文件夹id、或者"root"(代表个人盘根目录);
- * [name]: 显示的名称
- * [user]: Basic Auth 的用户名
- * [pass]: Basic Auth 的密码
- * [protect_file_link]: Basic Auth 是否用于保护文件链接,默认值(不设置时)为 false,即不保护文件链接(方便 直链下载/外部播放 等)
- * 每个盘的 Basic Auth 都可以单独设置。Basic Auth 默认保护该盘下所有文件夹/子文件夹路径
- * 【注意】默认不保护文件链接,这样可以方便 直链下载/外部播放;
- * 如果要保护文件链接,需要将 protect_file_link 设置为 true,此时如果要进行外部播放等操作,需要将 host 替换为 user:pass@host 的 形式
- * 不需要 Basic Auth 的盘,保持 user 和 pass 同时为空即可。(直接不设置也可以)
- * 【注意】对于id设置为为子文件夹id的盘将不支持搜索功能(不影响其他盘)。
- */
- "roots": [
- {
- id: "",
- name: "TeamDrive",
- pass: "",
- },
- {
- id: "root",
- name: "PrivateDrive",
- user: '',
- pass: "",
- protect_file_link: true
- },
- {
- id: "",
- name: "folder1",
- pass: "",
- }
- ],
- "default_gd": 0,
- /**
- * 文件列表页面每页显示的数量。【推荐设置值为 100 到 1000 之间】;
- * 如果设置大于1000,会导致请求 drive api 时出错;
- * 如果设置的值过小,会导致文件列表页面滚动条增量加载(分页加载)失效;
- * 此值的另一个作用是,如果目录内文件数大于此设置值(即需要多页展示的),将会对首次列目录结果进行缓存。
- */
- "files_list_page_size": 50,
- /**
- * 搜索结果页面每页显示的数量。【推荐设置值为 50 到 1000 之间】;
- * 如果设置大于1000,会导致请求 drive api 时出错;
- * 如果设置的值过小,会导致搜索结果页面滚动条增量加载(分页加载)失效;
- * 此值的大小影响搜索操作的响应速度。
- */
- "search_result_list_page_size": 50,
- // 确认有 cors 用途的可以开启
- "enable_cors_file_down": false,
- /**
- * 上面的 basic auth 已经包含了盘内全局保护的功能。所以默认不再去认证 .password 文件内的密码;
- * 如果在全局认证的基础上,仍需要给某些目录单独进行 .password 文件内的密码验证的话,将此选项设置为 true;
- * 【注意】如果开启了 .password 文件密码验证,每次列目录都会额外增加查询目录内 .password 文件是否存在的开销。
- */
- "enable_password_file_verify": true
+ // 强烈推荐使用自己的 client_id 和 client_secret
+ client_id: "",
+ client_secret: "",
+ refresh_token: "", // 授权 token
+ /**
+ * 设置要显示的多个云端硬盘;按格式添加多个
+ * [id]: 可以是 团队盘id、子文件夹id、或者"root"(代表个人盘根目录);
+ * [name]: 显示的名称
+ * [user]: Basic Auth 的用户名
+ * [pass]: Basic Auth 的密码
+ * [protect_file_link]: Basic Auth 是否用于保护文件链接,默认值(不设置时)为 false,即不保护文件链接(方便 直链下载/外部播放 等)
+ * 每个盘的 Basic Auth 都可以单独设置。Basic Auth 默认保护该盘下所有文件夹/子文件夹路径
+ * 【注意】默认不保护文件链接,这样可以方便 直链下载/外部播放;
+ * 如果要保护文件链接,需要将 protect_file_link 设置为 true,此时如果要进行外部播放等操作,需要将 host 替换为 user:pass@host 的 形式
+ * 不需要 Basic Auth 的盘,保持 user 和 pass 同时为空即可。(直接不设置也可以)
+ * 【注意】对于id设置为为子文件夹id的盘将不支持搜索功能(不影响其他盘)。
+ */
+ roots: [
+ {
+ id: "",
+ name: "TeamDrive",
+ pass: "",
+ },
+ {
+ id: "root",
+ name: "PrivateDrive",
+ user: "",
+ pass: "",
+ protect_file_link: true,
+ },
+ {
+ id: "",
+ name: "folder1",
+ pass: "",
+ },
+ ],
+ default_gd: 0,
+ /**
+ * 文件列表页面每页显示的数量。【推荐设置值为 100 到 1000 之间】;
+ * 如果设置大于1000,会导致请求 drive api 时出错;
+ * 如果设置的值过小,会导致文件列表页面滚动条增量加载(分页加载)失效;
+ * 此值的另一个作用是,如果目录内文件数大于此设置值(即需要多页展示的),将会对首次列目录结果进行缓存。
+ */
+ files_list_page_size: 50,
+ /**
+ * 搜索结果页面每页显示的数量。【推荐设置值为 50 到 1000 之间】;
+ * 如果设置大于1000,会导致请求 drive api 时出错;
+ * 如果设置的值过小,会导致搜索结果页面滚动条增量加载(分页加载)失效;
+ * 此值的大小影响搜索操作的响应速度。
+ */
+ search_result_list_page_size: 50,
+ // 确认有 cors 用途的可以开启
+ enable_cors_file_down: false,
+ /**
+ * 上面的 basic auth 已经包含了盘内全局保护的功能。所以默认不再去认证 .password 文件内的密码;
+ * 如果在全局认证的基础上,仍需要给某些目录单独进行 .password 文件内的密码验证的话,将此选项设置为 true;
+ * 【注意】如果开启了 .password 文件密码验证,每次列目录都会额外增加查询目录内 .password 文件是否存在的开销。
+ */
+ enable_password_file_verify: true,
};
var themeOptions = {
- //可选默认系统语言:en/zh-chs/zh-cht
- languages: 'en'
-}
+ //可选默认系统语言:en/zh-chs/zh-cht
+ languages: "en",
+ render: {
+ head_md: false,
+ readme_md: false,
+ // 是否显示文件/文件夹描述(默认不显示)
+ // Show file/folder description or not (not shown by default)
+ desc: false
+ },
+};
/**
* global functions
*/
const FUNCS = {
- /**
- * 转换成针对谷歌搜索词法相对安全的搜索关键词
- */
- formatSearchKeyword: function (keyword) {
- let nothing = "";
- let space = " ";
- if (!keyword) return nothing;
- return keyword.replace(/(!=)|['"=<>/\\:]/g, nothing)
- .replace(/[,,|(){}]/g, space)
- .trim()
- }
-
+ /**
+ * 转换成针对谷歌搜索词法相对安全的搜索关键词
+ */
+ formatSearchKeyword: function(keyword) {
+ let nothing = "";
+ let space = " ";
+ if (!keyword) return nothing;
+ return keyword
+ .replace(/(!=)|['"=<>/\\:]/g, nothing)
+ .replace(/[,,|(){}]/g, space)
+ .trim();
+ },
};
/**
@@ -93,21 +100,21 @@ const FUNCS = {
* @type {{folder_mime_type: string, default_file_fields: string, gd_root_type: {share_drive: number, user_drive: number, sub_folder: number}}}
*/
const CONSTS = new (class {
- default_file_fields = 'parents,id,name,mimeType,modifiedTime,createdTime,fileExtension,size';
- gd_root_type = {
- user_drive: 0,
- share_drive: 1,
- sub_folder: 2
- };
- folder_mime_type = 'application/vnd.google-apps.folder';
+ default_file_fields =
+ "parents,id,name,mimeType,modifiedTime,createdTime,fileExtension,size";
+ gd_root_type = {
+ user_drive: 0,
+ share_drive: 1,
+ sub_folder: 2,
+ };
+ folder_mime_type = "application/vnd.google-apps.folder";
})();
-
// gd instances
var gds = [];
function html(current_drive_order = 0, model = {}) {
- return `
+ return `
@@ -118,8 +125,14 @@ function html(current_drive_order = 0, model = {}) {
@import url(https://cloud.jsonpop.cn/go2index/v2.0.0_beta/dist/style.css);
@@ -130,10 +143,10 @@ function html(current_drive_order = 0, model = {}) {
`;
-};
+}
-addEventListener('fetch', event => {
- event.respondWith(handleRequest(event.request));
+addEventListener("fetch", (event) => {
+ event.respondWith(handleRequest(event.request));
});
/**
@@ -141,178 +154,200 @@ addEventListener('fetch', event => {
* @param {Request} request
*/
async function handleRequest(request) {
- if (gds.length === 0) {
- for (let i = 0; i < authConfig.roots.length; i++) {
- const gd = new googleDrive(authConfig, i);
- await gd.init();
- gds.push(gd)
- }
- // 这个操作并行,提高效率
- let tasks = [];
- gds.forEach(gd => {
- tasks.push(gd.initRootType());
- });
- for (let task of tasks) {
- await task;
- }
+ if (gds.length === 0) {
+ for (let i = 0; i < authConfig.roots.length; i++) {
+ const gd = new googleDrive(authConfig, i);
+ await gd.init();
+ gds.push(gd);
}
-
- // 从 path 中提取 drive order
- // 并根据 drive order 获取对应的 gd instance
- let gd;
- let url = new URL(request.url);
- let path = url.pathname;
-
- /**
- * 重定向至起始页
- * @returns {Response}
- */
- function redirectToIndexPage() {
- return new Response('', {status: 301, headers: {'Location': `/${authConfig.default_gd}:/`}});
+ // 这个操作并行,提高效率
+ let tasks = [];
+ gds.forEach((gd) => {
+ tasks.push(gd.initRootType());
+ });
+ for (let task of tasks) {
+ await task;
}
+ }
- if (path == '/') return redirectToIndexPage();
- if (path.toLowerCase() == '/favicon.ico') {
- // 后面可以找一个 favicon
- return new Response('', {status: 404})
- }
+ // 从 path 中提取 drive order
+ // 并根据 drive order 获取对应的 gd instance
+ let gd;
+ let url = new URL(request.url);
+ let path = url.pathname;
- // 特殊命令格式
- const command_reg = /^\/(?\d+):(?[a-zA-Z0-9]+)(\/.*)?$/g;
- const match = command_reg.exec(path);
- let command;
- if (match) {
- const num = match.groups.num;
- const order = Number(num);
- if (order >= 0 && order < gds.length) {
- gd = gds[order];
- } else {
- return redirectToIndexPage()
- }
- // basic auth
- for (const r = gd.basicAuthResponse(request); r;) return r;
- command = match.groups.command;
+ /**
+ * 重定向至起始页
+ * @returns {Response}
+ */
+ function redirectToIndexPage() {
+ return new Response("", {
+ status: 301,
+ headers: { Location: `/${authConfig.default_gd}:/` },
+ });
+ }
- // 搜索
- if (command === 'search') {
- if (request.method === 'POST') {
- // 搜索结果
- return handleSearch(request, gd);
- } else {
- const params = url.searchParams;
- // 搜索页面
- return new Response(html(gd.order, {
- q: params.get("q") || '',
- is_search_page: true,
- root_type: gd.root_type
- }),
- {
- status: 200,
- headers: {'Content-Type': 'text/html; charset=utf-8'}
- });
- }
- } else if (command === 'id2path' && request.method === 'POST') {
- return handleId2Path(request, gd)
- } else if (command === 'view'){
- const params = url.searchParams;
- return gd.view(params.get("url"), request.headers.get('Range'));
- } else if (command!=='down' && request.method === 'GET'){
- return new Response(html(gd.order, {root_type: gd.root_type}), {
- status: 200,
- headers: {'Content-Type': 'text/html; charset=utf-8'}
- });
- }
- }
- const reg = new RegExp(`^(/\\d+:)${command}/`, 'g');
- path = path.replace(reg,(p1,p2)=>{
- return p2+'/'
- })
- // 期望的 path 格式
- const common_reg = /^\/\d+:\/.*$/g;
- try {
- if (!path.match(common_reg)) {
- return redirectToIndexPage();
- }
- let split = path.split("/");
- let order = Number(split[1].slice(0, -1));
- if (order >= 0 && order < gds.length) {
- gd = gds[order];
- } else {
- return redirectToIndexPage()
- }
- } catch (e) {
- return redirectToIndexPage()
- }
+ if (path == "/") return redirectToIndexPage();
+ if (path.toLowerCase() == "/favicon.ico") {
+ // 后面可以找一个 favicon
+ return new Response("", { status: 404 });
+ }
- // basic auth
- // for (const r = gd.basicAuthResponse(request); r;) return r;
- const basic_auth_res = gd.basicAuthResponse(request);
- path = path.replace(gd.url_path_prefix, '') || '/';
- if (request.method == 'POST') {
- return basic_auth_res || apiRequest(request, gd);
- }
-
- let action = url.searchParams.get('a');
-
- if (path.substr(-1) == '/' || action != null) {
- return basic_auth_res || new Response(html(gd.order, {root_type: gd.root_type}), {
- status: 200,
- headers: {'Content-Type': 'text/html; charset=utf-8'}
- });
+ // 特殊命令格式
+ const command_reg = /^\/(?\d+):(?[a-zA-Z0-9]+)(\/.*)?$/g;
+ const match = command_reg.exec(path);
+ let command;
+ if (match) {
+ const num = match.groups.num;
+ const order = Number(num);
+ if (order >= 0 && order < gds.length) {
+ gd = gds[order];
} else {
- if (path.split('/').pop().toLowerCase() == ".password") {
- return basic_auth_res || new Response("", {status: 404});
- }
- let file = await gd.file(path);
- let range = request.headers.get('Range');
- if (gd.root.protect_file_link && basic_auth_res) return basic_auth_res;
- const is_down = !(command && command=='down');
- return gd.down(file.id, range, is_down);
+ return redirectToIndexPage();
}
+ // basic auth
+ for (const r = gd.basicAuthResponse(request); r; ) return r;
+ command = match.groups.command;
+
+ // 搜索
+ if (command === "search") {
+ if (request.method === "POST") {
+ // 搜索结果
+ return handleSearch(request, gd);
+ } else {
+ const params = url.searchParams;
+ // 搜索页面
+ return new Response(
+ html(gd.order, {
+ q: params.get("q") || "",
+ is_search_page: true,
+ root_type: gd.root_type,
+ }),
+ {
+ status: 200,
+ headers: { "Content-Type": "text/html; charset=utf-8" },
+ }
+ );
+ }
+ } else if (command === "id2path" && request.method === "POST") {
+ return handleId2Path(request, gd);
+ } else if (command === "view") {
+ const params = url.searchParams;
+ return gd.view(params.get("url"), request.headers.get("Range"));
+ } else if (command !== "down" && request.method === "GET") {
+ return new Response(html(gd.order, { root_type: gd.root_type }), {
+ status: 200,
+ headers: { "Content-Type": "text/html; charset=utf-8" },
+ });
+ }
+ }
+ const reg = new RegExp(`^(/\\d+:)${command}/`, "g");
+ path = path.replace(reg, (p1, p2) => {
+ return p2 + "/";
+ });
+ // 期望的 path 格式
+ const common_reg = /^\/\d+:\/.*$/g;
+ try {
+ if (!path.match(common_reg)) {
+ return redirectToIndexPage();
+ }
+ let split = path.split("/");
+ let order = Number(split[1].slice(0, -1));
+ if (order >= 0 && order < gds.length) {
+ gd = gds[order];
+ } else {
+ return redirectToIndexPage();
+ }
+ } catch (e) {
+ return redirectToIndexPage();
+ }
+
+ // basic auth
+ // for (const r = gd.basicAuthResponse(request); r;) return r;
+ const basic_auth_res = gd.basicAuthResponse(request);
+ path = path.replace(gd.url_path_prefix, "") || "/";
+ if (request.method == "POST") {
+ return basic_auth_res || apiRequest(request, gd);
+ }
+
+ let action = url.searchParams.get("a");
+
+ if (path.substr(-1) == "/" || action != null) {
+ return (
+ basic_auth_res ||
+ new Response(html(gd.order, { root_type: gd.root_type }), {
+ status: 200,
+ headers: { "Content-Type": "text/html; charset=utf-8" },
+ })
+ );
+ } else {
+ if (
+ path
+ .split("/")
+ .pop()
+ .toLowerCase() == ".password"
+ ) {
+ return basic_auth_res || new Response("", { status: 404 });
+ }
+ let file = await gd.file(path);
+ let range = request.headers.get("Range");
+ if (gd.root.protect_file_link && basic_auth_res) return basic_auth_res;
+ const is_down = !(command && command == "down");
+ return gd.down(file.id, range, is_down);
+ }
}
-
async function apiRequest(request, gd) {
- let url = new URL(request.url);
- let path = url.pathname;
- path = path.replace(gd.url_path_prefix, '') || '/';
+ let url = new URL(request.url);
+ let path = url.pathname;
+ path = path.replace(gd.url_path_prefix, "") || "/";
- let option = {status: 200, headers: {'Access-Control-Allow-Origin': '*'}}
+ let option = { status: 200, headers: { "Access-Control-Allow-Origin": "*" } };
- if (path.substr(-1) == '/') {
- let deferred_pass = gd.password(path);
- let body = await request.text();
- body = JSON.parse(body);
- // 这样可以提升首次列目录时的速度。缺点是,如果password验证失败,也依然会产生列目录的开销
- let deferred_list_result = gd.list(path, body.page_token, Number(body.page_index));
+ if (path.substr(-1) == "/") {
+ let deferred_pass = gd.password(path);
+ let body = await request.text();
+ body = JSON.parse(body);
+ // 这样可以提升首次列目录时的速度。缺点是,如果password验证失败,也依然会产生列目录的开销
+ let deferred_list_result = gd.list(
+ path,
+ body.page_token,
+ Number(body.page_index)
+ );
- // check .password file, if `enable_password_file_verify` is true
- if (authConfig['enable_password_file_verify']) {
- let password = await gd.password(path);
- // console.log("dir password", password);
- if (password && password.replace("\n", "") !== body.password) {
- let html = `{"error": {"code": 401,"message": "password error."}}`;
- return new Response(html, option);
- }
- }
-
- let list_result = await deferred_list_result;
- return new Response(JSON.stringify(list_result), option);
- } else {
- let file = await gd.file(path);
- let range = request.headers.get('Range');
- return new Response(JSON.stringify(file));
+ // check .password file, if `enable_password_file_verify` is true
+ if (authConfig["enable_password_file_verify"]) {
+ let password = await gd.password(path);
+ // console.log("dir password", password);
+ if (password && password.replace("\n", "") !== body.password) {
+ let html = `{"error": {"code": 401,"message": "password error."}}`;
+ return new Response(html, option);
+ }
}
+
+ let list_result = await deferred_list_result;
+ return new Response(JSON.stringify(list_result), option);
+ } else {
+ let file = await gd.file(path);
+ let range = request.headers.get("Range");
+ return new Response(JSON.stringify(file));
+ }
}
// 处理 search
async function handleSearch(request, gd) {
- const option = {status: 200, headers: {'Access-Control-Allow-Origin': '*'}};
- let body = await request.text();
- body = JSON.parse(body);
- let search_result = await
- gd.search(body.q || '', body.page_token, Number(body.page_index));
- return new Response(JSON.stringify(search_result), option);
+ const option = {
+ status: 200,
+ headers: { "Access-Control-Allow-Origin": "*" },
+ };
+ let body = await request.text();
+ body = JSON.parse(body);
+ let search_result = await gd.search(
+ body.q || "",
+ body.page_token,
+ Number(body.page_index)
+ );
+ return new Response(JSON.stringify(search_result), option);
}
/**
@@ -322,45 +357,48 @@ async function handleSearch(request, gd) {
* @returns {Promise} 【注意】如果从前台接收的id代表的项目不在目标gd盘下,那么response会返回给前台一个空字符串""
*/
async function handleId2Path(request, gd) {
- const option = {status: 200, headers: {'Access-Control-Allow-Origin': '*'}};
- let body = await request.text();
- body = JSON.parse(body);
- let path = await gd.findPathById(body.id);
- return new Response(path || '', option);
+ const option = {
+ status: 200,
+ headers: { "Access-Control-Allow-Origin": "*" },
+ };
+ let body = await request.text();
+ body = JSON.parse(body);
+ let path = await gd.findPathById(body.id);
+ return new Response(path || "", option);
}
class googleDrive {
- constructor(authConfig, order) {
- // 每个盘对应一个order,对应一个gd实例
- this.order = order;
- this.root = authConfig.roots[order];
- this.root.protect_file_link = this.root.protect_file_link || false;
- this.url_path_prefix = `/${order}:`;
- this.authConfig = authConfig;
- // TODO: 这些缓存的失效刷新策略,后期可以制定一下
- // path id
- this.paths = [];
- // path file
- this.files = [];
- // path pass
- this.passwords = [];
- // id <-> path
- this.id_path_cache = {};
- this.id_path_cache[this.root['id']] = '/';
- this.paths["/"] = this.root['id'];
- /*if (this.root['pass'] != "") {
+ constructor(authConfig, order) {
+ // 每个盘对应一个order,对应一个gd实例
+ this.order = order;
+ this.root = authConfig.roots[order];
+ this.root.protect_file_link = this.root.protect_file_link || false;
+ this.url_path_prefix = `/${order}:`;
+ this.authConfig = authConfig;
+ // TODO: 这些缓存的失效刷新策略,后期可以制定一下
+ // path id
+ this.paths = [];
+ // path file
+ this.files = [];
+ // path pass
+ this.passwords = [];
+ // id <-> path
+ this.id_path_cache = {};
+ this.id_path_cache[this.root["id"]] = "/";
+ this.paths["/"] = this.root["id"];
+ /*if (this.root['pass'] != "") {
this.passwords['/'] = this.root['pass'];
}*/
- // this.init();
- }
+ // this.init();
+ }
- /**
- * 初次授权;然后获取 user_drive_real_root_id
- * @returns {Promise}
- */
- async init() {
- await this.accessToken();
- /*await (async () => {
+ /**
+ * 初次授权;然后获取 user_drive_real_root_id
+ * @returns {Promise}
+ */
+ async init() {
+ await this.accessToken();
+ /*await (async () => {
// 只获取1次
if (authConfig.user_drive_real_root_id) return;
const root_obj = await (gds[0] || this).findItemById('root');
@@ -368,167 +406,175 @@ class googleDrive {
authConfig.user_drive_real_root_id = root_obj.id
}
})();*/
- // 等待 user_drive_real_root_id ,只获取1次
- if (authConfig.user_drive_real_root_id) return;
- const root_obj = await (gds[0] || this).findItemById('root');
- if (root_obj && root_obj.id) {
- authConfig.user_drive_real_root_id = root_obj.id
- }
+ // 等待 user_drive_real_root_id ,只获取1次
+ if (authConfig.user_drive_real_root_id) return;
+ const root_obj = await (gds[0] || this).findItemById("root");
+ if (root_obj && root_obj.id) {
+ authConfig.user_drive_real_root_id = root_obj.id;
}
+ }
- /**
- * 获取根目录类型,设置到 root_type
- * @returns {Promise}
- */
- async initRootType() {
- const root_id = this.root['id'];
- const types = CONSTS.gd_root_type;
- if (root_id === 'root' || root_id === authConfig.user_drive_real_root_id) {
- this.root_type = types.user_drive;
- } else {
- const obj = await this.getShareDriveObjById(root_id);
- this.root_type = obj ? types.share_drive : types.sub_folder;
- }
+ /**
+ * 获取根目录类型,设置到 root_type
+ * @returns {Promise}
+ */
+ async initRootType() {
+ const root_id = this.root["id"];
+ const types = CONSTS.gd_root_type;
+ if (root_id === "root" || root_id === authConfig.user_drive_real_root_id) {
+ this.root_type = types.user_drive;
+ } else {
+ const obj = await this.getShareDriveObjById(root_id);
+ this.root_type = obj ? types.share_drive : types.sub_folder;
}
+ }
- /**
- * Returns a response that requires authorization, or null
- * @param request
- * @returns {Response|null}
- */
- basicAuthResponse(request) {
- const user = this.root.user || '',
- pass = this.root.pass || '',
- _401 = new Response('Unauthorized', {
- headers: {'WWW-Authenticate': `Basic realm="goindex:drive:${this.order}"`},
- status: 401
- });
- if (user || pass) {
- const auth = request.headers.get('Authorization')
- if (auth) {
- try {
- const [received_user, received_pass] = atob(auth.split(' ').pop()).split(':');
- return (received_user === user && received_pass === pass) ? null : _401;
- } catch (e) {}
- }
- } else return null;
- return _401;
- }
-
- async view(url, range = '', inline = true) {
- let requestOption = await this.requestOption();
- requestOption.headers['Range'] = range;
- let res = await fetch(url, requestOption);
- const {headers} = res = new Response(res.body, res)
- this.authConfig.enable_cors_file_down && headers.append('Access-Control-Allow-Origin', '*');
- inline === true && headers.set('Content-Disposition', 'inline');
- return res;
- }
-
- async down(id, range = '', inline = false) {
- let url = `https://www.googleapis.com/drive/v3/files/${id}?alt=media`;
- let requestOption = await this.requestOption();
- requestOption.headers['Range'] = range;
- let res = await fetch(url, requestOption);
- const {headers} = res = new Response(res.body, res)
- this.authConfig.enable_cors_file_down && headers.append('Access-Control-Allow-Origin', '*');
- inline === true && headers.set('Content-Disposition', 'inline');
- return res;
+ /**
+ * Returns a response that requires authorization, or null
+ * @param request
+ * @returns {Response|null}
+ */
+ basicAuthResponse(request) {
+ const user = this.root.user || "",
+ pass = this.root.pass || "",
+ _401 = new Response("Unauthorized", {
+ headers: {
+ "WWW-Authenticate": `Basic realm="goindex:drive:${this.order}"`,
+ },
+ status: 401,
+ });
+ if (user || pass) {
+ const auth = request.headers.get("Authorization");
+ if (auth) {
+ try {
+ const [received_user, received_pass] = atob(
+ auth.split(" ").pop()
+ ).split(":");
+ return received_user === user && received_pass === pass ? null : _401;
+ } catch (e) {}
}
+ } else return null;
+ return _401;
+ }
- async file(path) {
- if (typeof this.files[path] == 'undefined') {
- this.files[path] = await this._file(path);
- }
- return this.files[path];
+ async view(url, range = "", inline = true) {
+ let requestOption = await this.requestOption();
+ requestOption.headers["Range"] = range;
+ let res = await fetch(url, requestOption);
+ const { headers } = (res = new Response(res.body, res));
+ this.authConfig.enable_cors_file_down &&
+ headers.append("Access-Control-Allow-Origin", "*");
+ inline === true && headers.set("Content-Disposition", "inline");
+ return res;
+ }
+
+ async down(id, range = "", inline = false) {
+ let url = `https://www.googleapis.com/drive/v3/files/${id}?alt=media`;
+ let requestOption = await this.requestOption();
+ requestOption.headers["Range"] = range;
+ let res = await fetch(url, requestOption);
+ const { headers } = (res = new Response(res.body, res));
+ this.authConfig.enable_cors_file_down &&
+ headers.append("Access-Control-Allow-Origin", "*");
+ inline === true && headers.set("Content-Disposition", "inline");
+ return res;
+ }
+
+ async file(path) {
+ if (typeof this.files[path] == "undefined") {
+ this.files[path] = await this._file(path);
+ }
+ return this.files[path];
+ }
+
+ async _file(path) {
+ let arr = path.split("/");
+ let name = arr.pop();
+ name = decodeURIComponent(name).replace(/\'/g, "\\'");
+ let dir = arr.join("/") + "/";
+ // console.log(name, dir);
+ let parent = await this.findPathId(dir);
+ // console.log(parent);
+ let url = "https://www.googleapis.com/drive/v3/files";
+ let params = { includeItemsFromAllDrives: true, supportsAllDrives: true };
+ params.q = `'${parent}' in parents and name = '${name}' and trashed = false`;
+ params.fields =
+ "files(id, name, mimeType, size ,createdTime, modifiedTime, iconLink, thumbnailLink)";
+ url += "?" + this.enQuery(params);
+ let requestOption = await this.requestOption();
+ let response = await fetch(url, requestOption);
+ let obj = await response.json();
+ // console.log(obj);
+ return obj.files[0];
+ }
+
+ // 通过reqeust cache 来缓存
+ async list(path, page_token = null, page_index = 0) {
+ if (this.path_children_cache == undefined) {
+ // { :[ {nextPageToken:'',data:{}}, {nextPageToken:'',data:{}} ...], ...}
+ this.path_children_cache = {};
}
- async _file(path) {
- let arr = path.split('/');
- let name = arr.pop();
- name = decodeURIComponent(name).replace(/\'/g, "\\'");
- let dir = arr.join('/') + '/';
- // console.log(name, dir);
- let parent = await this.findPathId(dir);
- // console.log(parent);
- let url = 'https://www.googleapis.com/drive/v3/files';
- let params = {'includeItemsFromAllDrives': true, 'supportsAllDrives': true};
- params.q = `'${parent}' in parents and name = '${name}' and trashed = false`;
- params.fields = "files(id, name, mimeType, size ,createdTime, modifiedTime, iconLink, thumbnailLink)";
- url += '?' + this.enQuery(params);
- let requestOption = await this.requestOption();
- let response = await fetch(url, requestOption);
- let obj = await response.json();
- // console.log(obj);
- return obj.files[0];
+ if (
+ this.path_children_cache[path] &&
+ this.path_children_cache[path][page_index] &&
+ this.path_children_cache[path][page_index].data
+ ) {
+ let child_obj = this.path_children_cache[path][page_index];
+ return {
+ nextPageToken: child_obj.nextPageToken || null,
+ curPageIndex: page_index,
+ data: child_obj.data,
+ };
}
- // 通过reqeust cache 来缓存
- async list(path, page_token = null, page_index = 0) {
- if (this.path_children_cache == undefined) {
- // { :[ {nextPageToken:'',data:{}}, {nextPageToken:'',data:{}} ...], ...}
- this.path_children_cache = {};
- }
-
- if (this.path_children_cache[path]
- && this.path_children_cache[path][page_index]
- && this.path_children_cache[path][page_index].data
- ) {
- let child_obj = this.path_children_cache[path][page_index];
- return {
- nextPageToken: child_obj.nextPageToken || null,
- curPageIndex: page_index,
- data: child_obj.data
- };
- }
-
- let id = await this.findPathId(path);
- let result = await this._ls(id, page_token, page_index);
- let data = result.data;
- // 对有多页的,进行缓存
- if (result.nextPageToken && data.files) {
- if (!Array.isArray(this.path_children_cache[path])) {
- this.path_children_cache[path] = []
- }
- this.path_children_cache[path][Number(result.curPageIndex)] = {
- nextPageToken: result.nextPageToken,
- data: data
- };
- }
-
- return result
+ let id = await this.findPathId(path);
+ let result = await this._ls(id, page_token, page_index);
+ let data = result.data;
+ // 对有多页的,进行缓存
+ if (result.nextPageToken && data.files) {
+ if (!Array.isArray(this.path_children_cache[path])) {
+ this.path_children_cache[path] = [];
+ }
+ this.path_children_cache[path][Number(result.curPageIndex)] = {
+ nextPageToken: result.nextPageToken,
+ data: data,
+ };
}
+ return result;
+ }
- async _ls(parent, page_token = null, page_index = 0) {
- // console.log("_ls", parent);
+ async _ls(parent, page_token = null, page_index = 0) {
+ // console.log("_ls", parent);
- if (parent == undefined) {
- return null;
- }
- let obj;
- let params = {'includeItemsFromAllDrives': true, 'supportsAllDrives': true};
- params.q = `'${parent}' in parents and trashed = false AND name !='.password'`;
- params.orderBy = 'folder,name,modifiedTime desc';
- params.fields = "nextPageToken, files(id, name, mimeType, size , modifiedTime, thumbnailLink, description)";
- params.pageSize = this.authConfig.files_list_page_size;
+ if (parent == undefined) {
+ return null;
+ }
+ let obj;
+ let params = { includeItemsFromAllDrives: true, supportsAllDrives: true };
+ params.q = `'${parent}' in parents and trashed = false AND name !='.password'`;
+ params.orderBy = "folder,name,modifiedTime desc";
+ params.fields =
+ "nextPageToken, files(id, name, mimeType, size , modifiedTime, thumbnailLink, description)";
+ params.pageSize = this.authConfig.files_list_page_size;
- if (page_token) {
- params.pageToken = page_token;
- }
- let url = 'https://www.googleapis.com/drive/v3/files';
- url += '?' + this.enQuery(params);
- let requestOption = await this.requestOption();
- let response = await fetch(url, requestOption);
- obj = await response.json();
+ if (page_token) {
+ params.pageToken = page_token;
+ }
+ let url = "https://www.googleapis.com/drive/v3/files";
+ url += "?" + this.enQuery(params);
+ let requestOption = await this.requestOption();
+ let response = await fetch(url, requestOption);
+ obj = await response.json();
- return {
- nextPageToken: obj.nextPageToken || null,
- curPageIndex: page_index,
- data: obj
- };
+ return {
+ nextPageToken: obj.nextPageToken || null,
+ curPageIndex: page_index,
+ data: obj,
+ };
- /*do {
+ /*do {
if (pageToken) {
params.pageToken = pageToken;
}
@@ -540,332 +586,345 @@ class googleDrive {
files.push(...obj.files);
pageToken = obj.nextPageToken;
} while (pageToken);*/
+ }
+ async password(path) {
+ if (this.passwords[path] !== undefined) {
+ return this.passwords[path];
}
- async password(path) {
- if (this.passwords[path] !== undefined) {
- return this.passwords[path];
- }
+ // console.log("load", path, ".password", this.passwords[path]);
- // console.log("load", path, ".password", this.passwords[path]);
-
- let file = await this.file(path + '.password');
- if (file == undefined) {
- this.passwords[path] = null;
- } else {
- let url = `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`;
- let requestOption = await this.requestOption();
- let response = await this.fetch200(url, requestOption);
- this.passwords[path] = await response.text();
- }
-
- return this.passwords[path];
+ let file = await this.file(path + ".password");
+ if (file == undefined) {
+ this.passwords[path] = null;
+ } else {
+ let url = `https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`;
+ let requestOption = await this.requestOption();
+ let response = await this.fetch200(url, requestOption);
+ this.passwords[path] = await response.text();
}
+ return this.passwords[path];
+ }
- /**
- * 通过 id 获取 share drive 信息
- * @param any_id
- * @returns {Promise} 任何非正常情况都返回 null
- */
- async getShareDriveObjById(any_id) {
- if (!any_id) return null;
- if ('string' !== typeof any_id) return null;
+ /**
+ * 通过 id 获取 share drive 信息
+ * @param any_id
+ * @returns {Promise} 任何非正常情况都返回 null
+ */
+ async getShareDriveObjById(any_id) {
+ if (!any_id) return null;
+ if ("string" !== typeof any_id) return null;
- let url = `https://www.googleapis.com/drive/v3/drives/${any_id}`;
- let requestOption = await this.requestOption();
- let res = await fetch(url, requestOption);
- let obj = await res.json();
- if (obj && obj.id) return obj;
+ let url = `https://www.googleapis.com/drive/v3/drives/${any_id}`;
+ let requestOption = await this.requestOption();
+ let res = await fetch(url, requestOption);
+ let obj = await res.json();
+ if (obj && obj.id) return obj;
- return null
+ return null;
+ }
+
+ /**
+ * 搜索
+ * @returns {Promise<{data: null, nextPageToken: null, curPageIndex: number}>}
+ */
+ async search(origin_keyword, page_token = null, page_index = 0) {
+ const types = CONSTS.gd_root_type;
+ const is_user_drive = this.root_type === types.user_drive;
+ const is_share_drive = this.root_type === types.share_drive;
+
+ const empty_result = {
+ nextPageToken: null,
+ curPageIndex: page_index,
+ data: null,
+ };
+
+ if (!is_user_drive && !is_share_drive) {
+ return empty_result;
+ }
+ let keyword = FUNCS.formatSearchKeyword(origin_keyword);
+ if (!keyword) {
+ // 关键词为空,返回
+ return empty_result;
+ }
+ let words = keyword.split(/\s+/);
+ let name_search_str = `name contains '${words.join(
+ "' AND name contains '"
+ )}'`;
+
+ // corpora 为 user 是个人盘 ,为 drive 是团队盘。配合 driveId
+ let params = {};
+ if (is_user_drive) {
+ params.corpora = "user";
+ }
+ if (is_share_drive) {
+ params.corpora = "drive";
+ params.driveId = this.root.id;
+ // This parameter will only be effective until June 1, 2020. Afterwards shared drive items will be included in the results.
+ params.includeItemsFromAllDrives = true;
+ params.supportsAllDrives = true;
+ }
+ if (page_token) {
+ params.pageToken = page_token;
+ }
+ params.q = `trashed = false AND name !='.password' AND (${name_search_str})`;
+ params.fields =
+ "nextPageToken, files(id, name, mimeType, size , modifiedTime, thumbnailLink, description)";
+ params.pageSize = this.authConfig.search_result_list_page_size;
+ // params.orderBy = 'folder,name,modifiedTime desc';
+
+ let url = "https://www.googleapis.com/drive/v3/files";
+ url += "?" + this.enQuery(params);
+ // console.log(params)
+ let requestOption = await this.requestOption();
+ let response = await fetch(url, requestOption);
+ let res_obj = await response.json();
+
+ return {
+ nextPageToken: res_obj.nextPageToken || null,
+ curPageIndex: page_index,
+ data: res_obj,
+ };
+ }
+
+ /**
+ * 一层一层的向上获取这个文件或文件夹的上级文件夹的 file 对象。注意:会很慢!!!
+ * 最多向上寻找到当前 gd 对象的根目录 (root id)
+ * 只考虑一条单独的向上链。
+ * 【注意】如果此id代表的项目不在目标gd盘下,那么此函数会返回null
+ *
+ * @param child_id
+ * @param contain_myself
+ * @returns {Promise<[]>}
+ */
+ async findParentFilesRecursion(child_id, contain_myself = true) {
+ const gd = this;
+ const gd_root_id = gd.root.id;
+ const user_drive_real_root_id = authConfig.user_drive_real_root_id;
+ const is_user_drive = gd.root_type === CONSTS.gd_root_type.user_drive;
+
+ // 自下向上查询的终点目标id
+ const target_top_id = is_user_drive ? user_drive_real_root_id : gd_root_id;
+ const fields = CONSTS.default_file_fields;
+
+ // [{},{},...]
+ const parent_files = [];
+ let meet_top = false;
+
+ async function addItsFirstParent(file_obj) {
+ if (!file_obj) return;
+ if (!file_obj.parents) return;
+ if (file_obj.parents.length < 1) return;
+
+ // ['','',...]
+ let p_ids = file_obj.parents;
+ if (p_ids && p_ids.length > 0) {
+ // its first parent
+ const first_p_id = p_ids[0];
+ if (first_p_id === target_top_id) {
+ meet_top = true;
+ return;
+ }
+ const p_file_obj = await gd.findItemById(first_p_id);
+ if (p_file_obj && p_file_obj.id) {
+ parent_files.push(p_file_obj);
+ await addItsFirstParent(p_file_obj);
+ }
+ }
}
+ const child_obj = await gd.findItemById(child_id);
+ if (contain_myself) {
+ parent_files.push(child_obj);
+ }
+ await addItsFirstParent(child_obj);
- /**
- * 搜索
- * @returns {Promise<{data: null, nextPageToken: null, curPageIndex: number}>}
- */
- async search(origin_keyword, page_token = null, page_index = 0) {
- const types = CONSTS.gd_root_type;
- const is_user_drive = this.root_type === types.user_drive;
- const is_share_drive = this.root_type === types.share_drive;
+ return meet_top ? parent_files : null;
+ }
- const empty_result = {
- nextPageToken: null,
- curPageIndex: page_index,
- data: null
- };
-
- if (!is_user_drive && !is_share_drive) {
- return empty_result;
- }
- let keyword = FUNCS.formatSearchKeyword(origin_keyword);
- if (!keyword) {
- // 关键词为空,返回
- return empty_result;
- }
- let words = keyword.split(/\s+/);
- let name_search_str = `name contains '${words.join("' AND name contains '")}'`;
-
- // corpora 为 user 是个人盘 ,为 drive 是团队盘。配合 driveId
- let params = {};
- if (is_user_drive) {
- params.corpora = 'user'
- }
- if (is_share_drive) {
- params.corpora = 'drive';
- params.driveId = this.root.id;
- // This parameter will only be effective until June 1, 2020. Afterwards shared drive items will be included in the results.
- params.includeItemsFromAllDrives = true;
- params.supportsAllDrives = true;
- }
- if (page_token) {
- params.pageToken = page_token;
- }
- params.q = `trashed = false AND name !='.password' AND (${name_search_str})`;
- params.fields = "nextPageToken, files(id, name, mimeType, size , modifiedTime, thumbnailLink, description)";
- params.pageSize = this.authConfig.search_result_list_page_size;
- // params.orderBy = 'folder,name,modifiedTime desc';
-
- let url = 'https://www.googleapis.com/drive/v3/files';
- url += '?' + this.enQuery(params);
- // console.log(params)
- let requestOption = await this.requestOption();
- let response = await fetch(url, requestOption);
- let res_obj = await response.json();
-
- return {
- nextPageToken: res_obj.nextPageToken || null,
- curPageIndex: page_index,
- data: res_obj
- };
+ /**
+ * 获取相对于本盘根目录的path
+ * @param child_id
+ * @returns {Promise} 【注意】如果此id代表的项目不在目标gd盘下,那么此方法会返回空字符串""
+ */
+ async findPathById(child_id) {
+ if (this.id_path_cache[child_id]) {
+ return this.id_path_cache[child_id];
}
+ const p_files = await this.findParentFilesRecursion(child_id);
+ if (!p_files || p_files.length < 1) return "";
- /**
- * 一层一层的向上获取这个文件或文件夹的上级文件夹的 file 对象。注意:会很慢!!!
- * 最多向上寻找到当前 gd 对象的根目录 (root id)
- * 只考虑一条单独的向上链。
- * 【注意】如果此id代表的项目不在目标gd盘下,那么此函数会返回null
- *
- * @param child_id
- * @param contain_myself
- * @returns {Promise<[]>}
- */
- async findParentFilesRecursion(child_id, contain_myself = true) {
- const gd = this;
- const gd_root_id = gd.root.id;
- const user_drive_real_root_id = authConfig.user_drive_real_root_id;
- const is_user_drive = gd.root_type === CONSTS.gd_root_type.user_drive;
+ let cache = [];
+ // 把查出来的每一级的path和id都缓存一下
+ p_files.forEach((value, idx) => {
+ const is_folder =
+ idx === 0 ? p_files[idx].mimeType === CONSTS.folder_mime_type : true;
+ let path =
+ "/" +
+ p_files
+ .slice(idx)
+ .map((it) => it.name)
+ .reverse()
+ .join("/");
+ if (is_folder) path += "/";
+ cache.push({ id: p_files[idx].id, path: path });
+ });
- // 自下向上查询的终点目标id
- const target_top_id = is_user_drive ? user_drive_real_root_id : gd_root_id;
- const fields = CONSTS.default_file_fields;
+ cache.forEach((obj) => {
+ this.id_path_cache[obj.id] = obj.path;
+ this.paths[obj.path] = obj.id;
+ });
- // [{},{},...]
- const parent_files = [];
- let meet_top = false;
-
- async function addItsFirstParent(file_obj) {
- if (!file_obj) return;
- if (!file_obj.parents) return;
- if (file_obj.parents.length < 1) return;
-
- // ['','',...]
- let p_ids = file_obj.parents;
- if (p_ids && p_ids.length > 0) {
- // its first parent
- const first_p_id = p_ids[0];
- if (first_p_id === target_top_id) {
- meet_top = true;
- return;
- }
- const p_file_obj = await gd.findItemById(first_p_id);
- if (p_file_obj && p_file_obj.id) {
- parent_files.push(p_file_obj);
- await addItsFirstParent(p_file_obj);
- }
- }
- }
-
- const child_obj = await gd.findItemById(child_id);
- if (contain_myself) {
- parent_files.push(child_obj);
- }
- await addItsFirstParent(child_obj);
-
- return meet_top ? parent_files : null
- }
-
- /**
- * 获取相对于本盘根目录的path
- * @param child_id
- * @returns {Promise} 【注意】如果此id代表的项目不在目标gd盘下,那么此方法会返回空字符串""
- */
- async findPathById(child_id) {
- if (this.id_path_cache[child_id]) {
- return this.id_path_cache[child_id];
- }
-
- const p_files = await this.findParentFilesRecursion(child_id);
- if (!p_files || p_files.length < 1) return '';
-
- let cache = [];
- // 把查出来的每一级的path和id都缓存一下
- p_files.forEach((value, idx) => {
- const is_folder = idx === 0 ? (p_files[idx].mimeType === CONSTS.folder_mime_type) : true;
- let path = '/' + p_files.slice(idx).map(it => it.name).reverse().join('/');
- if (is_folder) path += '/';
- cache.push({id: p_files[idx].id, path: path})
- });
-
- cache.forEach((obj) => {
- this.id_path_cache[obj.id] = obj.path;
- this.paths[obj.path] = obj.id
- });
-
- /*const is_folder = p_files[0].mimeType === CONSTS.folder_mime_type;
+ /*const is_folder = p_files[0].mimeType === CONSTS.folder_mime_type;
let path = '/' + p_files.map(it => it.name).reverse().join('/');
if (is_folder) path += '/';*/
- return cache[0].path;
+ return cache[0].path;
+ }
+
+ // 根据id获取file item
+ async findItemById(id) {
+ const is_user_drive = this.root_type === CONSTS.gd_root_type.user_drive;
+ let url = `https://www.googleapis.com/drive/v3/files/${id}?fields=${
+ CONSTS.default_file_fields
+ }${is_user_drive ? "" : "&supportsAllDrives=true"}`;
+ let requestOption = await this.requestOption();
+ let res = await fetch(url, requestOption);
+ return await res.json();
+ }
+
+ async findPathId(path) {
+ let c_path = "/";
+ let c_id = this.paths[c_path];
+
+ let arr = path.trim("/").split("/");
+ for (let name of arr) {
+ c_path += name + "/";
+
+ if (typeof this.paths[c_path] == "undefined") {
+ let id = await this._findDirId(c_id, name);
+ this.paths[c_path] = id;
+ }
+
+ c_id = this.paths[c_path];
+ if (c_id == undefined || c_id == null) {
+ break;
+ }
+ }
+ // console.log(this.paths);
+ return this.paths[path];
+ }
+
+ async _findDirId(parent, name) {
+ name = decodeURIComponent(name).replace(/\'/g, "\\'");
+
+ // console.log("_findDirId", parent, name);
+
+ if (parent == undefined) {
+ return null;
}
-
- // 根据id获取file item
- async findItemById(id) {
- const is_user_drive = this.root_type === CONSTS.gd_root_type.user_drive;
- let url = `https://www.googleapis.com/drive/v3/files/${id}?fields=${CONSTS.default_file_fields}${is_user_drive ? '' : '&supportsAllDrives=true'}`;
- let requestOption = await this.requestOption();
- let res = await fetch(url, requestOption);
- return await res.json()
+ let url = "https://www.googleapis.com/drive/v3/files";
+ let params = { includeItemsFromAllDrives: true, supportsAllDrives: true };
+ params.q = `'${parent}' in parents and mimeType = 'application/vnd.google-apps.folder' and name = '${name}' and trashed = false`;
+ params.fields = "nextPageToken, files(id, name, mimeType)";
+ url += "?" + this.enQuery(params);
+ let requestOption = await this.requestOption();
+ let response = await fetch(url, requestOption);
+ let obj = await response.json();
+ if (obj.files[0] == undefined) {
+ return null;
}
+ return obj.files[0].id;
+ }
- async findPathId(path) {
- let c_path = '/';
- let c_id = this.paths[c_path];
-
- let arr = path.trim('/').split('/');
- for (let name of arr) {
- c_path += name + '/';
-
- if (typeof this.paths[c_path] == 'undefined') {
- let id = await this._findDirId(c_id, name);
- this.paths[c_path] = id;
- }
-
- c_id = this.paths[c_path];
- if (c_id == undefined || c_id == null) {
- break;
- }
- }
- // console.log(this.paths);
- return this.paths[path];
+ 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 _findDirId(parent, name) {
- name = decodeURIComponent(name).replace(/\'/g, "\\'");
+ 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",
+ };
- // console.log("_findDirId", parent, name);
+ let requestOption = {
+ method: "POST",
+ headers: headers,
+ body: this.enQuery(post_data),
+ };
- if (parent == undefined) {
- return null;
- }
+ const response = await fetch(url, requestOption);
+ return await response.json();
+ }
- let url = 'https://www.googleapis.com/drive/v3/files';
- let params = {'includeItemsFromAllDrives': true, 'supportsAllDrives': true};
- params.q = `'${parent}' in parents and mimeType = 'application/vnd.google-apps.folder' and name = '${name}' and trashed = false`;
- params.fields = "nextPageToken, files(id, name, mimeType)";
- url += '?' + this.enQuery(params);
- let requestOption = await this.requestOption();
- let response = await fetch(url, requestOption);
- let obj = await response.json();
- if (obj.files[0] == undefined) {
- return null;
- }
- return obj.files[0].id;
+ async fetch200(url, requestOption) {
+ let response;
+ for (let i = 0; i < 3; i++) {
+ response = await fetch(url, requestOption);
+ console.log(response.status);
+ if (response.status != 403) {
+ break;
+ }
+ await this.sleep(800 * (i + 1));
}
+ return response;
+ }
- 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 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("&");
+ }
- 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 fetch200(url, requestOption) {
- let response;
- for (let i = 0; i < 3; i++) {
- response = await fetch(url, requestOption);
- console.log(response.status);
- if (response.status != 403) {
- break;
- }
- await this.sleep(800 * (i + 1));
- }
- return response;
- }
-
- 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('&');
- }
-
- sleep(ms) {
- return new Promise(function (resolve, reject) {
- let i = 0;
- setTimeout(function () {
- console.log('sleep' + ms);
- i++;
- if (i >= 2) reject(new Error('i>=2'));
- else resolve(i);
- }, ms);
- })
- }
+ sleep(ms) {
+ return new Promise(function(resolve, reject) {
+ let i = 0;
+ setTimeout(function() {
+ console.log("sleep" + ms);
+ i++;
+ if (i >= 2) reject(new Error("i>=2"));
+ else resolve(i);
+ }, ms);
+ });
+ }
}
-String.prototype.trim = function (char) {
- if (char) {
- return this.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '');
- }
- return this.replace(/^\s+|\s+$/g, '');
+String.prototype.trim = function(char) {
+ if (char) {
+ return this.replace(
+ new RegExp("^\\" + char + "+|\\" + char + "+$", "g"),
+ ""
+ );
+ }
+ return this.replace(/^\s+|\s+$/g, "");
};
diff --git a/package-lock.json b/package-lock.json
index 7222de0..8c682a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12677,7 +12677,7 @@
},
"webpack-bundle-analyzer": {
"version": "3.7.0",
- "resolved": "https://registry.npm.taobao.org/webpack-bundle-analyzer/download/webpack-bundle-analyzer-3.7.0.tgz?cache=0&sync_timestamp=1586846559504&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-bundle-analyzer%2Fdownload%2Fwebpack-bundle-analyzer-3.7.0.tgz",
+ "resolved": "https://registry.npm.taobao.org/webpack-bundle-analyzer/download/webpack-bundle-analyzer-3.7.0.tgz?cache=0&sync_timestamp=1586846510646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fwebpack-bundle-analyzer%2Fdownload%2Fwebpack-bundle-analyzer-3.7.0.tgz",
"integrity": "sha1-hNpDTolEKJm4hNmtOORm0NsCpW8=",
"dev": true,
"requires": {
diff --git a/public/index.html b/public/index.html
index f3480ff..f3f1d89 100644
--- a/public/index.html
+++ b/public/index.html
@@ -14,7 +14,7 @@
<%= htmlWebpackPlugin.options.title %>
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
diff --git a/src/utils/AcrouUtil.js b/src/utils/AcrouUtil.js
index 6f028cb..fa7d0b2 100644
--- a/src/utils/AcrouUtil.js
+++ b/src/utils/AcrouUtil.js
@@ -1,37 +1,34 @@
import axios from "@utils/axios";
let Base64 = require("js-base64").Base64;
-// const exts = [
-// "html",
-// "php",
-// "css",
-// "go",
-// "java",
-// "js",
-// "json",
-// "py",
-// "txt",
-// "sh",
-// "md",
-// "mp4",
-// "webm",
-// "mkv",
-// "bmp",
-// "jpg",
-// "jpeg",
-// "png",
-// "gif",
-// ];
+const text_exts = [
+ "html",
+ "php",
+ "css",
+ "go",
+ "java",
+ "js",
+ "json",
+ "txt",
+ "sh",
+ "md",
+];
+const video_exts = ["mp4", "webm", "mkv", "m3u8"];
+const image_exts = ["bmp", "jpg", "jpeg", "png", "gif"];
+const pdf_exts = ["pdf"];
export const encodePath = (path) => {
return path.replace(/(.*)/, (p1, p2) => {
- return p2.replace().replace(/\//g, "%2F").replace(/#/g, "%23")
- })
+ return p2
+ .replace()
+ .replace(/\//g, "%2F")
+ .replace(/#/g, "%23");
+ });
//return path.replace().replace("/", "%2F").replace("#", "%23")
-}
+};
export const checkoutPath = (path, file) => {
- path = encodePath(path)
+ path = encodePath(path);
if (file.mimeType === "application/vnd.google-apps.folder") {
if (path.substr(-1) !== "/") {
path += "/";
@@ -47,25 +44,25 @@ export const checkView = (path) => {
.pop()
.toLowerCase();
let base64Path = encode64(path);
- if ("|html|php|css|go|java|js|json|txt|sh|md|".indexOf(`|${ext}|`) >= 0) {
+ if (text_exts.indexOf(`${ext}`) != -1) {
path = path.replace(/\/(\d+:)\/.*/, (p1, p2) => {
return `/${p2}text/${base64Path}`;
});
}
- if ("|pdf|".indexOf(`|${ext}|`) >= 0) {
+ if (pdf_exts.indexOf(`${ext}`) != -1) {
path = path.replace(/\/(\d+:)\/.*/, (p1, p2) => {
return `/${p2}pdf/${base64Path}`;
});
}
- if ("|mp4|webm|mkv|".indexOf(`|${ext}|`) >= 0) {
+ if (video_exts.indexOf(`${ext}`) != -1) {
path = path.replace(/\/(\d+:)\/.*/, (p1, p2) => {
return `/${p2}video/${base64Path}`;
});
}
- if ("|bmp|jpg|jpeg|png|gif|".indexOf(`|${ext}|`) >= 0) {
+ if (image_exts.indexOf(`${ext}`) != -1) {
path = path.replace(/\/(\d+:)\/.*/, (p1, p2) => {
return `/${p2}image/${base64Path}`;
});
@@ -73,27 +70,16 @@ export const checkView = (path) => {
return path;
};
-export const getQueryString = (path, param) => {
- if (!path) {
- return "";
- }
- var args = getURLParameters(path);
- return args[param] ? args[param] : "";
+export const checkExtends = (path) => {
+ let name = path.split("/").pop();
+ let ext = name
+ .split(".")
+ .pop()
+ .toLowerCase();
+ let exts = text_exts.concat(...video_exts,...image_exts,...pdf_exts);
+ return exts.indexOf(`${ext}`) != -1;
};
-export const getURLParameters = (url) =>
- url
- .match(/([^?=&]+)(=([^&]*))/g)
- .reduce(
- (a, v) => (
- (a[v.slice(0, v.indexOf("="))] = v.slice(v.indexOf("=") + 1)), a
- ), {}
- );
-
-// console.log(getURLParameters("/Movies/xx.mp4?a=view&y=123"));
-
-//console.log(getQueryString("/Movies/xx.mp4?a=view&y=123", "y"));
-
export const encode64 = (str) => {
return Base64.encodeURI(str);
};
@@ -182,51 +168,63 @@ export function formatFileSize(bytes) {
return bytes;
}
-
/** 日期格式化
- * @param {Number String Date}
+ * @param {Number String Date}
* @param {String} 'YYYY-MM-DD HH:mm:ss EEE' 年(Y)、月(M)、日(D)、12小时(h)、24小时(H)、分(m)、秒(s)、毫秒(S)、周(E)、季度(q)
* @return {String}
* @example XDate.format(new Date(), "YYYY-MM-DD") ==> 2017-08-23
*/
export function formatDate(date, fmt) {
- fmt = fmt || 'YYYY-MM-DD HH:mm:ss';
- if (typeof date === 'string') {
+ fmt = fmt || "YYYY-MM-DD HH:mm:ss";
+ if (typeof date === "string") {
// date = new Date(date.replace(/-/g, '/'))
- date = new Date(date)
+ date = new Date(date);
}
- if (typeof date === 'number') {
- date = new Date(date)
+ if (typeof date === "number") {
+ date = new Date(date);
}
var o = {
- 'M+': date.getMonth() + 1,
- 'D+': date.getDate(),
- 'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
- 'H+': date.getHours(),
- 'm+': date.getMinutes(),
- 's+': date.getSeconds(),
- 'q+': Math.floor((date.getMonth() + 3) / 3),
- 'S': date.getMilliseconds()
- }
+ "M+": date.getMonth() + 1,
+ "D+": date.getDate(),
+ "h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
+ "H+": date.getHours(),
+ "m+": date.getMinutes(),
+ "s+": date.getSeconds(),
+ "q+": Math.floor((date.getMonth() + 3) / 3),
+ S: date.getMilliseconds(),
+ };
var week = {
- '0': '\u65e5',
- '1': '\u4e00',
- '2': '\u4e8c',
- '3': '\u4e09',
- '4': '\u56db',
- '5': '\u4e94',
- '6': '\u516d'
- }
+ "0": "\u65e5",
+ "1": "\u4e00",
+ "2": "\u4e8c",
+ "3": "\u4e09",
+ "4": "\u56db",
+ "5": "\u4e94",
+ "6": "\u516d",
+ };
if (/(Y+)/.test(fmt)) {
- fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
+ fmt = fmt.replace(
+ RegExp.$1,
+ (date.getFullYear() + "").substr(4 - RegExp.$1.length)
+ );
}
if (/(E+)/.test(fmt)) {
- fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '\u661f\u671f' : '\u5468') : '') + week[date.getDay() + ''])
+ fmt = fmt.replace(
+ RegExp.$1,
+ (RegExp.$1.length > 1
+ ? RegExp.$1.length > 2
+ ? "\u661f\u671f"
+ : "\u5468"
+ : "") + week[date.getDay() + ""]
+ );
}
for (var k in o) {
- if (new RegExp('(' + k + ')').test(fmt)) {
- fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
+ if (new RegExp("(" + k + ")").test(fmt)) {
+ fmt = fmt.replace(
+ RegExp.$1,
+ RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
+ );
}
}
return fmt;
-}
\ No newline at end of file
+}
diff --git a/src/views/common/BreadCrumb.vue b/src/views/common/BreadCrumb.vue
index ab31710..81d4b56 100644
--- a/src/views/common/BreadCrumb.vue
+++ b/src/views/common/BreadCrumb.vue
@@ -108,6 +108,13 @@ export default {
// height: 100%;
padding: 10px 0.75em;
}
+.level-left {
+ width: 95%;
+ .level-item {
+ display: initial;
+ width: 100%;
+ }
+}
.level-right {
.level-item {
// border-radius: 50%;
diff --git a/src/views/common/Navbar.vue b/src/views/common/Navbar.vue
index 9570dd9..3cdcee5 100644
--- a/src/views/common/Navbar.vue
+++ b/src/views/common/Navbar.vue
@@ -42,7 +42,7 @@
-
+
@@ -144,6 +147,10 @@ export default {
getCurrGD() {
return this.gds.filter((item) => item.name !== this.currgd.name);
},
+ showSearch() {
+ // 文件夹不支持搜索
+ return window.MODEL ? window.MODEL.root_type < 2 : true
+ },
},
watch: {
"$route.params.id": "chooseGD",
diff --git a/src/views/page/GoList.vue b/src/views/page/GoList.vue
index 5e94cbc..9b2f87a 100644
--- a/src/views/page/GoList.vue
+++ b/src/views/page/GoList.vue
@@ -1,6 +1,6 @@
-
+
-
+
-
+
@@ -28,8 +37,13 @@
-->
-
-
+
+
{
@@ -134,22 +149,28 @@ export default {
return a.isFolder ? -1 : 1;
});
},
- images () {
+ images() {
return this.buildFiles.filter(
(file) => file.mimeType.indexOf("image") != -1
);
},
+ renderHeadMD() {
+ return window.themeOptions.render.head_md || false;
+ },
+ renderReadMeMD() {
+ return window.themeOptions.render.readme_md || false;
+ },
},
- created () {
+ created() {
this.render();
},
methods: {
- pageLoad () {
+ pageLoad() {
if (!this.page.page_token) return;
this.page.page_index++;
this.render("scroll");
},
- render (scroll) {
+ render(scroll) {
if (scroll) {
this.busy = true;
} else {
@@ -201,7 +222,7 @@ export default {
this.$router.go(-1);
});
},
- checkPassword (path) {
+ checkPassword(path) {
var pass = prompt(this.$t("list.auth"), "");
localStorage.setItem("password" + path, pass);
if (pass != null && pass != "") {
@@ -210,7 +231,7 @@ export default {
this.$router.go(-1);
}
},
- copy (path) {
+ copy(path) {
let origin = window.location.origin;
path = origin + encodeURI(path);
this.$copyText(path)
@@ -228,17 +249,17 @@ export default {
});
});
},
- thum (url) {
+ thum(url) {
return url ? `/${this.$route.params.id}:view?url=${url}` : "";
},
- inited (viewer) {
+ inited(viewer) {
this.$viewer = viewer;
},
- go (file, target) {
+ go(file, target) {
if (file.mimeType.indexOf("image") != -1) {
this.viewer = true;
this.$nextTick(() => {
- let index = this.images.findIndex(item => item.path === file.path)
+ let index = this.images.findIndex((item) => item.path === file.path);
this.$viewer.view(index);
});
return;
@@ -253,7 +274,7 @@ export default {
window.open(path);
return;
}
- if (target === "down") {
+ if (target === "down" || (!checkExtends(path) && !file.isFolder)) {
let temp_path = this.$route.params.path ? this.$route.params.path : "";
location.href = `/${this.$route.params.id}:down/${temp_path}/${file.name}`;
return;
@@ -271,7 +292,7 @@ export default {
return;
}
},
- renderMd (files, path) {
+ renderMd(files, path) {
var cmd = this.$route.params.cmd;
if (cmd) {
return;
@@ -295,7 +316,7 @@ export default {
}
});
},
- goSearchResult (file, target) {
+ goSearchResult(file, target) {
this.loading = true;
let cur = window.current_drive_order;
axios
@@ -320,7 +341,7 @@ export default {
console.log(e);
});
},
- getIcon (type) {
+ getIcon(type) {
return "#" + (this.icon[type] ? this.icon[type] : "icon-weizhi");
},
},
diff --git a/src/views/page/components/list/index.vue b/src/views/page/components/list/index.vue
index 194e9fe..c7a7483 100644
--- a/src/views/page/components/list/index.vue
+++ b/src/views/page/components/list/index.vue
@@ -32,7 +32,11 @@
{{ file.name }}
-
+
{{ file.modifiedTime }}
@@ -107,6 +111,9 @@ export default {
},
];
},
+ isShowDesc() {
+ return window.themeOptions.render.desc || false;
+ },
},
};
|