diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..444e8b96 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/.gitignore b/.gitignore index a13dbe63..c19c6b16 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ _up0.sh .ossutil_checkpoint ossutil_output app.asar + + +#tool +.vscode/ diff --git a/Makefile b/Makefile index eac73a53..64e003fb 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -VERSION=1.7.3 +VERSION=1.9.5 NAME=oss-browser CUSTOM=./custom @@ -10,14 +10,16 @@ ZIP=node ../zip.js ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ ELECTRON_VERSION=1.8.4 BUILD=ELECTRON_MIRROR=$(ELECTRON_MIRROR) $(PKGER) ./dist $(NAME) --asar --overwrite --out=build --version $(ELECTRON_VERSION) --app-version $(VERSION) - +ELECTON=./node_modules/.bin/electron i: cnpm i clean: rm -rf dist node_modules build releases node/crc64/cpp-addon/node_modules node/crc64/electron-crc64-prebuild/node_modules node/ossstore/node_modules dev: - NODE_ENV=development electron . --inspect=5858 + NODE_ENV=development ${ELECTON} . --inspect=5858 +debug: + NODE_ENV=development ${ELECTON} . --inspect-brk=5858 run: custom=$(CUSTOM) npm run dev diff --git a/Readme.md b/README-CN.md similarity index 64% rename from Readme.md rename to README-CN.md index 1f7a5ed7..6e4e702a 100644 --- a/Readme.md +++ b/README-CN.md @@ -6,25 +6,29 @@ OSS Browser 提供类似 windows 资源管理器功能。用户可以很方便 > Electron 框架可以让你使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序。它是基于 node.js 和 Chromium 开源项目。Electron 可以打包出跨平台的程序,运行在 Mac,Windows 和 Linux 上。 -## 1. 客户端下载: +## 1. 支持平台 -最新版本`1.7.3`,下载地址如下,解压即可使用。 +Windows7 above, Linux and Mac,不建议使用windows XP平台和windows Server平台 -> [

Window x32 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-win32-ia32.zip) +## 2. 客户端下载: -> [

Window x64 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-win32-x64.zip) +最新版本`1.9.5`,下载地址如下,解压即可使用。 -> [

Mac zip 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-darwin-x64.zip) +> [

Window x32 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-win32-ia32.zip) -> [

Ubuntu x64 版

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-linux-x64.zip) +> [

Window x64 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-win32-x64.zip) -> [

Ubuntu x32 版

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-linux-ia32.zip) +> [

Mac zip 版下载

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-darwin-x64.zip) + +> [

Ubuntu x64 版

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-linux-x64.zip) + +> [

Ubuntu x32 版

](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-linux-ia32.zip) 其他版本暂不提供,可以自行 build。 > [所有版本下载](all-releases.md) -## 2. 功能介绍: +## 3. 功能介绍: ``` 功能Map @@ -71,9 +75,19 @@ OSS Browser 提供类似 windows 资源管理器功能。用户可以很方便 ![restore](preview/need-restore.png) -- 归档 bucket 下所有文件均为 Archive 存储类型, 需要恢复才能访问。 +- 归档 bucket 下所有文件均为 Archive 存储类型, 需要解冻才能访问。 + +### (7) 支持自定义域名(cname方式)访问(1.9.0版本开始支持) + +![cname模式](preview/cname.png) + +- cname模式需要用户在oss控制台上进行域名和bucket的绑定,使用cname模式ossbrowser上所有object的操作都会走自定义域名方式 + +### (7) 支持请求付费者模式访问(1.9.0版本开始支持) -## 3. 开发环境搭建 +![requestPay](preview/requestpay.png) + +## 4. 开发环境搭建 > 如果你要在此基础上开发,请按照以下步骤进行。 @@ -135,7 +149,7 @@ make build # build前端代码到dist目录 make win64 # 打包win64程序, 可选: mac, linux64,linux32,win32,win64,all. ``` -## 4. 代码结构 +## 5. 代码结构 ``` oss-browser/ @@ -154,14 +168,28 @@ oss-browser/ |-- main.js # 程序入口 ``` -## 5. 自定义 build +## 6. 自定义 build 请看这里: [自定义 build](custom/) -## 6. 关于贡献 +## 7. 关于贡献 + +- 如有建议或发现 bug,请直接开 issue或者提PR,PR必须merge请求到dev分支,我们会统一把dev分支合并到master并发布,感谢广大开发者参与。 -- 暂不接受代码贡献,如有建议或发现 bug,请直接开 issue。 +## 8. 注意事项 +- OSS Browser使用过程中,如果遇到问题可打开调试面板进行问题初步排查,可通过单击OSS Browser工具左上角图标连续10次弹出调试面板,针对每个操作OSS Browser埋的都有关键操作信息,同时控制台会实时同步错误信息,如果用户无法理解错误日志信息。请issue截图反馈@luozhang002进行排查 +- OSS Browser工具使用过程中尽量不要开本地代理或者VPN相关 +- 开发者如果是通过本地编译github仓库生产的oss browser工具,想要进行主进程和渲染进程相关代码的调试可以参考文档[debug](debug.md) -## 7. 开源 LICENSE +## 9. 开源 LICENSE [Apache License 2.0](LICENSE) + + + +## 10. Mac升级到10.15 以上打包问题修复 +Mac 新系统不在支持32位程序,打包windows包的wine需要使用64位系统,导致无法打包windows的包。 +修复方案 +1. brew install homebrew/cask/wine-stable +2. mv /usr/local/bin/wine /usr/local/bin/wine-old && mv /usr/local/bin/wine64 /usr/local/bin/wine +3. 下载 "https://github.com/electron/rcedit/releases/download/v1.1.1/rcedit-x64.exe", 重命为 "rcedit.exe" 然后替换 "node_modules/rcedit/bin/rcedit.exe" diff --git a/README.md b/README.md new file mode 100644 index 00000000..f92ed958 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Quick start + +ossbrowser is a graphical management tool developed by Alibaba Cloud. It provides features similar to those of Windows Explorer. Using ossbrowser, you can view, upload, download, and manage objects with ease. + +## [README of Chinese](https://github.com/aliyun/oss-browser/blob/master/README-CN.md) + +## Platform + +Windows7 above, Linux and Mac. We do not recommend using WindowsXP and WindowServer + +## Procedure + +1. Download and install ossbrowser. + + |Supported platform|Download link| + |:-----------------|:------------| + |Window x32|[Window x32](https://github.com/aliyun/oss-browser/blob/master/all-releases.md)| + |Window x64|[Window x64](https://github.com/aliyun/oss-browser/blob/master/all-releases.md)| + |MAC|[MAC](https://github.com/aliyun/oss-browser/blob/master/all-releases.md)| + |Linux x64|[Linux x64](https://github.com/aliyun/oss-browser/blob/master/all-releases.md)| + +2. Start and log on to ossbrowser. +3. Manage buckets. You can create a bucket, delete a bucket, modify the ACL for a bucket, and manage the fragments in a bucket. +4. Manage objects. You can upload \(resumable\), download \(resumable\), delete, copy, move, rename, search for, and preview an object, and modify the ACL or set an HTTP header for an object. + +## Debug + +If you encounter any problems during using ossbrowser, you can open the debug mode and observe the console panel. How to open +the debug mode,you can click the left icon ten times ,after 1.8.0 version you also open debug mode in settings pages + +![left-icon](preview/left-icon.png) + +![setting-page](preview/setting-debug.png) + +## Qr code +1. OssBrowser answering questions + +2. Group number:21985509 + +## Links +[ossbrowser](https://www.alibabacloud.com/help/doc-detail/61872.htm) + +## LICENSE + +[Apache License 2.0](LICENSE) diff --git a/all-releases.md b/all-releases.md index 8c9c6878..48a70515 100644 --- a/all-releases.md +++ b/all-releases.md @@ -4,6 +4,15 @@ ||Windows ia32|Windows x64| Mac(zip) |Linux ia32|Linux x64|Release note| |-----|-----|-----|-----|--------|--------|---| +|1.9.5|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.5/oss-browser-linux-x64.zip)|[1.9.5.md](release-notes/1.9.5.en-US.md)| +|1.9.4|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.4/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.4/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.4/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.4/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.4/oss-browser-linux-x64.zip)|[1.9.4.md](release-notes/1.9.4.en-US.md)| +|1.9.3|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.3/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.3/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.3/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.3/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.3/oss-browser-linux-x64.zip)|[1.9.3.md](release-notes/1.9.3.en-US.md)| +|1.9.2|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.2/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.2/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.2/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.2/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.2/oss-browser-linux-x64.zip)|[1.9.2.md](release-notes/1.9.2.en-US.md)| +|1.9.1|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.1/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.1/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.1/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.1/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.1/oss-browser-linux-x64.zip)|[1.9.1.md](release-notes/1.9.1.en-US.md)| +|1.9.0|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.0/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.0/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.0/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.0/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.9.0/oss-browser-linux-x64.zip)|[1.9.0.md](release-notes/1.9.0.en-US.md)| +|1.8.1|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.1/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.1/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.1/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.1/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.1/oss-browser-linux-x64.zip)|[1.8.1.md](release-notes/1.8.1.en-US.md)| +|1.8.0|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.0/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.0/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.0/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.0/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.8.0/oss-browser-linux-x64.zip)|[1.8.0.md](release-notes/1.8.0.en-US.md)| +|1.7.4|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.4/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.4/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.4/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.4/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.4/oss-browser-linux-x64.zip)|[1.7.4.md](release-notes/1.7.4.en-US.md)| |1.7.3|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.3/oss-browser-linux-x64.zip)|[1.7.3.md](release-notes/1.7.3.en-US.md)| |1.7.2|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.2/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.2/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.2/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.2/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.2/oss-browser-linux-x64.zip)|[1.7.2.md](release-notes/1.7.2.en-US.md)| |1.7.1|[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.1/oss-browser-win32-ia32.zip) |[Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.1/oss-browser-win32-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.1/oss-browser-darwin-x64.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.1/oss-browser-linux-ia32.zip) | [Download](https://oss-attachment.cn-hangzhou.oss.aliyun-inc.com/oss-browser/1.7.1/oss-browser-linux-x64.zip)|[1.7.1.md](release-notes/1.7.1.en-US.md)| diff --git a/app/components/filters/formater.js b/app/components/filters/formater.js index 948aedcf..89a1d2df 100644 --- a/app/components/filters/formater.js +++ b/app/components/filters/formater.js @@ -1,6 +1,11 @@ 'use strict'; angular.module('web') + .filter('trustAsResourceUrl', ['$sce', function($sce) { + return function(val) { + return $sce.trustAsResourceUrl(val); + }; + }]) .filter('sub', function(){ return function(s, len){ if(s.length < len) return s; diff --git a/app/components/services/file.s.js b/app/components/services/file.s.js index 9dc2af69..ecd5584f 100644 --- a/app/components/services/file.s.js +++ b/app/components/services/file.s.js @@ -1,6 +1,6 @@ angular.module('web') - .factory('fileSvs', ['$q', function($q){ + .factory('fileSvs', ['$q','Const',function($q,Const){ @@ -16,15 +16,20 @@ angular.module('web') ? item.name.toLowerCase().substring(item.name.lastIndexOf('.')+1) : ''; + if(Const.IMM_DOC_TYPES.indexOf(ext)!=-1){ + //IMM预览支持的文档类型 + return {type: 'doc', ext: [ext]}; + } + switch(ext){ case 'png': case 'jpg': case 'jpeg': case 'gif': return {type: 'picture', ext: [ext]}; - case 'doc': - case 'docx': - case 'pdf': return {type: 'doc', ext: [ext]}; + // case 'doc': + // case 'docx': + // case 'pdf': return {type: 'doc', ext: [ext]}; case 'mp4': return {type:'video', ext: [ext], mineType: 'video/mp4'}; case 'webm': return {type:'video', ext: [ext], mineType: 'video/webm'}; diff --git a/app/components/services/job-util.js b/app/components/services/job-util.js index 9c2622f6..dd563b8a 100644 --- a/app/components/services/job-util.js +++ b/app/components/services/job-util.js @@ -14,6 +14,7 @@ angular.module('web') case 'failed': return 'danger'; case 'finished': return 'success'; case 'stopped': return 'warning'; + case 'retrying': return 'warning'; default : return 'default'; } } @@ -26,6 +27,7 @@ angular.module('web') case 'finished': return T('status.finished');// '完成'; case 'stopped': return T('status.stopped');//'暂停'; case 'verifying': return T('status.verifying');//''; + case 'retrying': return T('status.retrying'); default : return T('status.waiting');//'等待'; } } diff --git a/app/components/services/oss-download-manager.js b/app/components/services/oss-download-manager.js index c167e31e..2c32c928 100644 --- a/app/components/services/oss-download-manager.js +++ b/app/components/services/oss-download-manager.js @@ -1,323 +1,339 @@ angular.module('web') .factory('ossDownloadManager', ['$q', '$state', '$timeout', 'AuthInfo', 'ossSvs2', 'Toast', 'Const', 'DelayDone', 'safeApply', 'settingsSvs', - function ($q, $state, $timeout, AuthInfo, ossSvs2, Toast, Const, DelayDone, safeApply, settingsSvs) { + function ($q, $state, $timeout, AuthInfo, ossSvs2, Toast, Const, DelayDone, safeApply, settingsSvs) { - var OssStore = require('./node/ossstore'); - var fs = require('fs'); - var path = require('path'); - var os = require('os'); + var OssStore = require('./node/ossstore'); + var fs = require('fs'); + var path = require('path'); + var os = require('os'); - var stopCreatingFlag = false; + var stopCreatingFlag = false; - var concurrency = 0; - var $scope; - return { - init: init, - createDownloadJobs: createDownloadJobs, - checkStart: checkStart, - saveProg: saveProg, + var concurrency = 0; + var $scope; + return { + init: init, + createDownloadJobs: createDownloadJobs, + checkStart: checkStart, + saveProg: saveProg, - stopCreatingJobs: function(){ - stopCreatingFlag=true; - } - }; - - - function init(scope) { - $scope = scope; - concurrency = 0; - $scope.lists.downloadJobList = []; - var arr = loadProg(); + stopCreatingJobs: function () { + stopCreatingFlag = true; + } + }; - //console.log('----load saving download jobs:' + arr.length); - var authInfo = AuthInfo.get(); + function init(scope) { + $scope = scope; + concurrency = 0; + $scope.lists.downloadJobList = []; + $scope.retryTimes = 0; + var arr = loadProg(); - angular.forEach(arr, function (n) { - var job = createJob(authInfo, n); - if(job.status=='waiting' || job.status=='running'|| job.status=='verifying') job.stop(); - addEvents(job); - }); - } + //console.log('----load saving download jobs:' + arr.length); - function addEvents(job) { - $scope.lists.downloadJobList.push(job); - $scope.calcTotalProg(); - safeApply($scope); - checkStart(); + var authInfo = AuthInfo.get(); - //save - saveProg(); + angular.forEach(arr, function (n) { + var job = createJob(authInfo, n); + if (job.status == 'waiting' || job.status == 'running' || job.status == 'verifying') job.stop(); + addEvents(job); + }); + } - job.on('partcomplete', function (prog) { + function addEvents(job) { + $scope.lists.downloadJobList.push(job); + $scope.calcTotalProg(); safeApply($scope); + checkStart(); + //save - saveProg($scope); - }); + saveProg(); + + job.on('partcomplete', function (prog) { + safeApply($scope); + //save + saveProg($scope); + }); + + job.on('statuschange', function (status, retryTimes) { + if (status == 'stopped') { + concurrency--; + checkStart(); + } + + if (status == 'retrying') { + $scope.retryTimes = retryTimes; + } + + safeApply($scope); + //save + saveProg(); + }); + job.on('speedChange', function () { + safeApply($scope); + }) - job.on('statuschange', function (status) { - if (status == 'stopped') { + job.on('complete', function () { concurrency--; checkStart(); - } - safeApply($scope); - //save - saveProg(); - }); - job.on('speedChange', function(){ - safeApply($scope); - }) + //$scope.$emit('needrefreshfilelists'); + }); - job.on('complete', function () { - concurrency--; - checkStart(); - //$scope.$emit('needrefreshfilelists'); - }); + job.on('error', function (err) { + console.error(err); + concurrency--; + checkStart(); + }); - job.on('error', function (err) { - console.error(err); - concurrency--; - checkStart(); - }); - - } - - //流控, 同时只能有 n 个上传任务. - function checkStart() { - var maxConcurrency = settingsSvs.maxDownloadJobCount.get(); - //console.log(concurrency , maxConcurrency); - concurrency = Math.max(0,concurrency); - if (concurrency < maxConcurrency) { - var arr = $scope.lists.downloadJobList; - for (var i = 0; i < arr.length; i++) { - if (concurrency >= maxConcurrency) return; - - var n = arr[i]; - if (n.status == 'waiting') { - n.start(); - concurrency++; + } + + //流控, 同时只能有 n 个上传任务. + function checkStart() { + var maxConcurrency = settingsSvs.maxDownloadJobCount.get(); + //console.log(concurrency , maxConcurrency); + concurrency = Math.max(0, concurrency); + if (concurrency < maxConcurrency) { + var arr = $scope.lists.downloadJobList; + for (var i = 0; i < arr.length; i++) { + if (concurrency >= maxConcurrency) return; + + var n = arr[i]; + if (n.status == 'waiting') { + n.start(); + concurrency++; + } } } } - } - - /** - * 下载 - * @param fromOssInfos {array} item={region, bucket, path, name, size=0, isFolder=false} 有可能是目录,需要遍历 - * @param toLocalPath {string} - * @param jobsAddedFn {Function} 加入列表完成回调方法, jobs列表已经稳定 - */ - function createDownloadJobs(fromOssInfos, toLocalPath, jobsAddedFn) { - stopCreatingFlag = false; - //console.log('--------downloadFilesHandler', fromOssInfos, toLocalPath); - var authInfo = AuthInfo.get(); - var dirPath = path.dirname(fromOssInfos[0].path); - - loop(fromOssInfos, function (jobs) { - - }, function(){ - if(jobsAddedFn) jobsAddedFn(); - }); - - function loop(arr, callFn, callFn2) { - var t = []; - var len = arr.length; - var c = 0; - var c2 =0; - - if(len==0){ - callFn(t); - callFn2(t); - return; - } - _kdig(); - function _kdig(){ - dig(arr[c], t, function(){ + /** + * 下载 + * @param fromOssInfos {array} item={region, bucket, path, name, size=0, isFolder=false} 有可能是目录,需要遍历 + * @param toLocalPath {string} + * @param jobsAddedFn {Function} 加入列表完成回调方法, jobs列表已经稳定 + */ + function createDownloadJobs(fromOssInfos, toLocalPath, jobsAddedFn) { + stopCreatingFlag = false; + //console.log('--------downloadFilesHandler', fromOssInfos, toLocalPath); + var authInfo = AuthInfo.get(); + var dirPath = path.dirname(fromOssInfos[0].path); + + loop(fromOssInfos, function (jobs) { + + }, function () { + if (jobsAddedFn) jobsAddedFn(); + }); - }, function(){ - c2++; - if(c2>=len){ - callFn2(t); - } - }); - c++; - if(c==len){ + function loop(arr, callFn, callFn2) { + var t = []; + var len = arr.length; + var c = 0; + var c2 = 0; + + if (len == 0) { callFn(t); + callFn2(t); + return; } - else{ - if(stopCreatingFlag){ - return; + _kdig(); + + function _kdig() { + dig(arr[c], t, function () { + + }, function () { + c2++; + if (c2 >= len) { + callFn2(t); + } + }); + c++; + if (c == len) { + callFn(t); } + else { + + if (stopCreatingFlag) { + return; + } - $timeout(_kdig,10); + $timeout(_kdig, 10); + } } - } - // angular.forEach(arr, function (n) { - // dig(n, function (jobs) { - // t = t.concat(jobs); - // c++; - // console.log(c,'/',len); - // if (c == len) callFn(t); - // }); - // }); - } + // angular.forEach(arr, function (n) { + // dig(n, function (jobs) { + // t = t.concat(jobs); + // c++; + // console.log(c,'/',len); + // if (c == len) callFn(t); + // }); + // }); + } - function dig(ossInfo, t, callFn, callFn2) { + function dig(ossInfo, t, callFn, callFn2) { - if(stopCreatingFlag){ - return; - } + if (stopCreatingFlag) { + return; + } - var fileName = path.basename(ossInfo.path); - var filePath = path.join(toLocalPath, path.relative(dirPath, ossInfo.path)); + var fileName = path.basename(ossInfo.path); + var filePath = path.join(toLocalPath, path.relative(dirPath, ossInfo.path)); - if (ossInfo.isFolder) { - //目录 - fs.mkdir(filePath, function (err) { + if (ossInfo.isFolder) { + //目录 + fs.mkdir(filePath, function (err) { - if(err && err.code!='EEXIST'){ - Toast.error('创建目录['+filePath+']失败:'+err.message); + if (err && err.code != 'EEXIST') { + Toast.error('创建目录[' + filePath + ']失败:' + err.message); return; - } - //遍历 oss 目录 - function progDig(marker){ - ossSvs2.listFiles(ossInfo.region, ossInfo.bucket, ossInfo.path, marker).then(function (result) { - - var arr2 = result.data; - arr2.forEach(function (n) { - n.region = ossInfo.region; - n.bucket = ossInfo.bucket; + } + + //遍历 oss 目录 + function progDig(marker) { + ossSvs2.listFiles(ossInfo.region, ossInfo.bucket, ossInfo.path, marker).then(function (result) { + + var arr2 = result.data; + arr2.forEach(function (n) { + n.region = ossInfo.region; + n.bucket = ossInfo.bucket; + }); + loop(arr2, function (jobs) { + t = t.concat(jobs); + if (result.marker) { + $timeout(function () { + progDig(result.marker); + }, 10); + } else { + if (callFn) callFn(); + } + }, callFn2); }); - loop(arr2, function (jobs) { - t=t.concat(jobs); - if(result.marker){ - $timeout(function(){ - progDig(result.marker); - },10); - }else{ - if(callFn)callFn(); - } - }, callFn2); - }); - } - progDig(); - }); - - } else { - //文件 - if (process.platform=='win32'){ - //修复window下,文件名含非法字符需要转义 - if(/[\/\\\:\<\>\?\*\"\|]/.test(fileName)){ - fileName = encodeURIComponent(fileName); - filePath = path.join(path.dirname(filePath), encodeURIComponent(path.basename(filePath))); + } + + progDig(); + }); + + } else { + //文件 + if (process.platform == 'win32') { + //修复window下,文件名含非法字符需要转义 + if (/[\/\\\:\<\>\?\*\"\|]/.test(fileName)) { + fileName = encodeURIComponent(fileName); + filePath = path.join(path.dirname(filePath), encodeURIComponent(path.basename(filePath))); + } } + var job = createJob(authInfo, { + region: ossInfo.region, + from: { + bucket: ossInfo.bucket, + key: ossInfo.path + }, + to: { + name: fileName, + path: filePath + } + }); + + addEvents(job); + + t.push(job); + + if (callFn) callFn(); + if (callFn2) callFn2(); } - var job = createJob(authInfo, { - region: ossInfo.region, - from: { - bucket: ossInfo.bucket, - key: ossInfo.path + } + } + + /** + * @param auth {id, secret} + * @param opt { region, from, to, ...} + * @param opt.from {bucket, key} + * @param opt.to {name, path} + * @return job { start(), stop(), status, progress } + */ + function createJob(auth, opt) { + + var cname = AuthInfo.get().cname || false + + var endpointname = cname ? auth.eptplcname : auth.eptpl + //stsToken + if (auth.stoken && auth.id.indexOf('STS.') == 0) { + var store = new OssStore({ + stsToken: { + Credentials: { + AccessKeyId: auth.id, + AccessKeySecret: auth.secret, + SecurityToken: auth.stoken + } }, - to: { - name: fileName, - path: filePath - } + endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, endpointname), + cname: cname }); - - addEvents(job); - - t.push(job); - - if(callFn)callFn(); - if(callFn2)callFn2(); } + else { + var store = new OssStore({ + aliyunCredential: { + accessKeyId: auth.id, + secretAccessKey: auth.secret + }, + endpoint: ossSvs2.getOssEndpoint(opt.region, opt.from.bucket, endpointname), + cname: cname + }); + } + return store.createDownloadJob(opt); } - } - /** - * @param auth {id, secret} - * @param opt { region, from, to, ...} - * @param opt.from {bucket, key} - * @param opt.to {name, path} - * @return job { start(), stop(), status, progress } - */ - function createJob(auth, opt) { - //stsToken - if(auth.stoken && auth.id.indexOf('STS.')==0){ - var store = new OssStore({ - stsToken: { - Credentials: { - AccessKeyId: auth.id, - AccessKeySecret: auth.secret, - SecurityToken: auth.stoken - } - }, - endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, auth.eptpl) - }); - } - else{ - var store = new OssStore({ - aliyunCredential: { - accessKeyId: auth.id, - secretAccessKey: auth.secret - }, - endpoint: ossSvs2.getOssEndpoint(opt.region, opt.from.bucket, auth.eptpl) - }); - } - return store.createDownloadJob(opt); - } - function saveProg() { + function saveProg() { - //console.log('request save:', t); - DelayDone.delayRun('save_download_prog', 1000, function () { + //console.log('request save:', t); + DelayDone.delayRun('save_download_prog', 1000, function () { - var t = []; - angular.forEach($scope.lists.downloadJobList, function (n) { + var t = []; + angular.forEach($scope.lists.downloadJobList, function (n) { - if (n.status == 'finished') return; + if (n.status == 'finished') return; - t.push({ - checkPoints: n.checkPoints, - region: n.region, - to: n.to, - from: n.from, - message: n.message, - status: n.status, - prog: n.prog + t.push({ + checkPoints: n.checkPoints, + region: n.region, + to: n.to, + from: n.from, + message: n.message, + status: n.status, + prog: n.prog + }); }); - }); - //console.log('save:', t); + //console.log('save:', t); - fs.writeFileSync(getDownProgFilePath(), JSON.stringify(t)); - $scope.calcTotalProg(); - },20); - } - - /** - * 获取保存的进度 - */ - function loadProg() { - try { - var data = fs.readFileSync(getDownProgFilePath()); - return JSON.parse(data ? data.toString() : '[]'); - } catch (e) { + fs.writeFileSync(getDownProgFilePath(), JSON.stringify(t)); + $scope.calcTotalProg(); + }, 20); + } + + /** + * 获取保存的进度 + */ + function loadProg() { + try { + var data = fs.readFileSync(getDownProgFilePath()); + return JSON.parse(data ? data.toString() : '[]'); + } catch (e) { + } + return []; } - return []; - } - //下载进度保存路径 - function getDownProgFilePath() { - var folder = path.join(os.homedir(), '.oss-browser'); - if(!fs.existsSync(folder)){ + //下载进度保存路径 + function getDownProgFilePath() { + var folder = path.join(os.homedir(), '.oss-browser'); + if (!fs.existsSync(folder)) { fs.mkdirSync(folder); + } + var username = AuthInfo.get().id || ''; + return path.join(folder, 'downprog_' + username + '.json'); } - var username = AuthInfo.get().id || ''; - return path.join(folder, 'downprog_' + username + '.json'); - } - }]); + }]); diff --git a/app/components/services/oss-upload-manager.js b/app/components/services/oss-upload-manager.js index 39bd54b1..5fbb66f8 100644 --- a/app/components/services/oss-upload-manager.js +++ b/app/components/services/oss-upload-manager.js @@ -1,5 +1,5 @@ angular.module('web') - .factory('ossUploadManager', ['$q', '$state','$timeout', 'ossSvs2', 'AuthInfo', 'Toast', 'Const', 'DelayDone', 'safeApply', 'settingsSvs', + .factory('ossUploadManager', ['$q', '$state', '$timeout', 'ossSvs2', 'AuthInfo', 'Toast', 'Const', 'DelayDone', 'safeApply', 'settingsSvs', function ($q, $state, $timeout, ossSvs2, AuthInfo, Toast, Const, DelayDone, safeApply, settingsSvs) { var OssStore = require('./node/ossstore'); @@ -19,7 +19,7 @@ angular.module('web') checkStart: checkStart, saveProg: saveProg, - stopCreatingJobs: function(){ + stopCreatingJobs: function () { stopCreatingFlag = true; } }; @@ -28,6 +28,7 @@ angular.module('web') $scope = scope; concurrency = 0; $scope.lists.uploadJobList = []; + $scope.retryTimes = 0; var arr = loadProg(); var authInfo = AuthInfo.get(); @@ -35,7 +36,7 @@ angular.module('web') angular.forEach(arr, function (n) { //console.log(n,'<====='); var job = createJob(authInfo, n); - if(job.status=='waiting' || job.status=='running'|| job.status=='verifying') job.stop(); + if (job.status == 'waiting' || job.status == 'running' || job.status == 'verifying' || job.status == 'retrying') job.stop(); addEvents(job); }); } @@ -55,18 +56,22 @@ angular.module('web') saveProg(); }); - job.on('statuschange', function (status) { + job.on('statuschange', function (status, retryTimes) { if (status == 'stopped') { concurrency--; - $timeout(checkStart,100); + $timeout(checkStart, 100); + } + + if (status == 'retrying') { + $scope.retryTimes = retryTimes; } safeApply($scope); //save saveProg(); }); - job.on('speedChange', function(){ + job.on('speedChange', function () { safeApply($scope); }) @@ -87,7 +92,7 @@ angular.module('web') //流控, 同时只能有 n 个上传任务. var maxConcurrency = settingsSvs.maxUploadJobCount.get(); //console.log(concurrency , maxConcurrency); - concurrency = Math.max(0,concurrency); + concurrency = Math.max(0, concurrency); if (concurrency < maxConcurrency) { var arr = $scope.lists.uploadJobList; for (var i = 0; i < arr.length; i++) { @@ -103,15 +108,15 @@ angular.module('web') } } - function checkNeedRefreshFileList(bucket, key){ + function checkNeedRefreshFileList(bucket, key) { - if($scope.currentInfo.bucket == bucket){ + if ($scope.currentInfo.bucket == bucket) { var p = path.dirname(key) + '/'; p = (p == './') ? '' : p; - if($scope.currentInfo.key == p){ - $scope.$emit('needrefreshfilelists'); + if ($scope.currentInfo.key == p) { + $scope.$emit('needrefreshfilelists'); } } } @@ -129,8 +134,8 @@ angular.module('web') var authInfo = AuthInfo.get(); - digArr(filePaths, function(){ - if(jobsAddingFn)jobsAddingFn(); + digArr(filePaths, function () { + if (jobsAddingFn) jobsAddingFn(); }); return; @@ -143,40 +148,41 @@ angular.module('web') var n = filePaths[c]; var dirPath = path.dirname(n); - if(stopCreatingFlag)return; + if (stopCreatingFlag) return; dig(filePaths[c], dirPath, function (jobs) { t = t.concat(jobs); c++; - if (c >= len){ + if (c >= len) { fn(t); } - else{ + else { _dig(); } }); } + _dig(); } - function loop(parentPath, dirPath, arr, callFn) { + function loop(parentPath, dirPath, arr, callFn) { var t = []; var len = arr.length; var c = 0; - if(len==0) callFn([]); + if (len == 0) callFn([]); else inDig(); //串行 function inDig() { - dig(path.join(parentPath, arr[c]), dirPath, function (jobs) { + dig(path.join(parentPath, arr[c]), dirPath, function (jobs) { t = t.concat(jobs); c++; //console.log(c,'/',len); if (c >= len) callFn(t); - else{ + else { - if(stopCreatingFlag){ + if (stopCreatingFlag) { return; } @@ -186,9 +192,9 @@ angular.module('web') } } - function dig(absPath, dirPath, callFn) { + function dig(absPath, dirPath, callFn) { - if(stopCreatingFlag){ + if (stopCreatingFlag) { return; } @@ -196,20 +202,20 @@ angular.module('web') var filePath = path.relative(dirPath, absPath); - if(path.sep!='/'){ + if (path.sep != '/') { //修复window下 \ 问题 filePath = filePath.replace(/\\/g, '/') } //修复window下 \ 问题 - filePath = bucketInfo.key ? (bucketInfo.key.replace(/(\/*$)/g, '') +'/'+ filePath ) : filePath; + filePath = bucketInfo.key ? (bucketInfo.key.replace(/(\/*$)/g, '') + '/' + filePath) : filePath; if (fs.statSync(absPath).isDirectory()) { //创建目录 - ossSvs2.createFolder(bucketInfo.region, bucketInfo.bucket, filePath+ '/').then(function(){ + ossSvs2.createFolder(bucketInfo.region, bucketInfo.bucket, filePath + '/').then(function () { //判断是否刷新文件列表 - checkNeedRefreshFileList(bucketInfo.bucket, filePath+ '/'); + checkNeedRefreshFileList(bucketInfo.bucket, filePath + '/'); }); //递归遍历目录 @@ -226,11 +232,11 @@ angular.module('web') console.log(err.stack); } else { - loop(absPath, dirPath, arr, function (jobs) { + loop(absPath, dirPath, arr, function (jobs) { - $timeout(function(){ + $timeout(function () { callFn(jobs); - },1); + }, 1); }); } @@ -252,28 +258,31 @@ angular.module('web') addEvents(job); - $timeout(function(){ + $timeout(function () { callFn([job]); - },1); + }, 1); } } } /** - * 创建单个job - * @param auth { id, secret} - * @param opt { region, from, to, progress, checkPoints, ...} - * @param opt.from {name, path} - * @param opt.to {bucket, key} - ... - * @return job { start(), stop(), status, progress } - job.events: statuschange, progress - */ + * 创建单个job + * @param auth { id, secret} + * @param opt { region, from, to, progress, checkPoints, ...} + * @param opt.from {name, path} + * @param opt.to {bucket, key} + ... + * @return job { start(), stop(), status, progress } + job.events: statuschange, progress + */ function createJob(auth, opt) { + var cname = AuthInfo.get().cname || false + var endpointname = cname ? auth.eptplcname : auth.eptpl + //stsToken - if(auth.stoken && auth.id.indexOf('STS.')==0){ + if (auth.stoken && auth.id.indexOf('STS.') == 0) { var store = new OssStore({ stsToken: { Credentials: { @@ -282,16 +291,18 @@ angular.module('web') SecurityToken: auth.stoken } }, - endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, auth.eptpl) + endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, endpointname), + cname: cname }); } - else{ + else { var store = new OssStore({ aliyunCredential: { accessKeyId: auth.id, secretAccessKey: auth.secret }, - endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, auth.eptpl) + endpoint: ossSvs2.getOssEndpoint(opt.region, opt.to.bucket, endpointname), + cname: cname }); } return store.createUploadJob(opt); @@ -353,8 +364,8 @@ angular.module('web') //上传进度保存路径 function getUpProgFilePath() { var folder = path.join(os.homedir(), '.oss-browser'); - if(!fs.existsSync(folder)){ - fs.mkdirSync(folder); + if (!fs.existsSync(folder)) { + fs.mkdirSync(folder); } var username = AuthInfo.get().id || ''; diff --git a/app/components/services/oss2.js b/app/components/services/oss2.js index 1a8a5b06..54fe4bdf 100644 --- a/app/components/services/oss2.js +++ b/app/components/services/oss2.js @@ -1,7 +1,6 @@ angular.module('web') .factory('ossSvs2', ['$q', '$rootScope', '$timeout', '$state', 'Toast', 'Const', 'AuthInfo', - function ($q, $rootScope, $timeout, $state, Toast, Const, AuthInfo) { - + function ($q, $rootScope, $timeout, $state, Toast, Const, AuthInfo,) { var NEXT_TICK = 1; var DEF_ADDR = 'oss://'; @@ -63,12 +62,14 @@ angular.module('web') function getClient2(opt) { var options = prepaireOptions(opt) // console.log(options) - var client = new OSS.Wrapper({ + var client = new OSS({ accessKeyId: options.accessKeyId, accessKeySecret: options.secretAccessKey, endpoint: options.endpoint, bucket: opt.bucket, stsToken: options.securityToken, + cname: options.cname, + isRequestPay: options.isRequestPayer }); console.log(OSS.version); return client; @@ -229,7 +230,7 @@ angular.module('web') if (itemsToDelete.length == 500 || (objectsCount != 0 && objectsCount + foldersCount == len)) { if (itemsToDelete.length > 1) { - client.deleteMulti(itemsToDelete).then(function (res) { + client.deleteMulti(itemsToDelete, {isRequestPay: true}).then(function (res) { c += itemsToDelete.length; progress.current += itemsToDelete.length; itemsToDelete.splice(0, itemsToDelete.length); @@ -245,7 +246,7 @@ angular.module('web') $timeout(dig, NEXT_TICK); }); } else { - client.delete(itemsToDelete[0]).then(function (res) { + client.delete(itemsToDelete[0], {isRequestPay: true}).then(function (res) { c += itemsToDelete.length; progress.current += itemsToDelete.length; itemsToDelete.splice(0, itemsToDelete.length); @@ -275,7 +276,7 @@ angular.module('web') return; } - client.delete(item.path).then(function (res) { + client.delete(item.path, {isRequestPay: true}).then(function (res) { c++; progress.current++; $timeout(dig, NEXT_TICK); @@ -298,6 +299,7 @@ angular.module('web') function stopCopyFiles() { stopCopyFilesFlag = true; } + /** * 批量复制或移动文件 * @param retion {string} 要求相同region @@ -403,7 +405,8 @@ angular.module('web') progress.errorCount++; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } t.push({ item: item, error: err @@ -412,13 +415,15 @@ angular.module('web') progress.current++; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } c++; //fix ubuntu $timeout(_dig, NEXT_TICK); }); } + _dig(); } @@ -545,7 +550,8 @@ angular.module('web') progress.total += len; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } function _() { @@ -582,7 +588,8 @@ angular.module('web') progress.errorCount++; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } terr.push({ item: items[c], error: err @@ -591,7 +598,8 @@ angular.module('web') progress.current++; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } $timeout(_, NEXT_TICK); }); } else { @@ -602,11 +610,13 @@ angular.module('web') progress.current++; if (progFn) try { progFn(progress); - } catch (e) {} + } catch (e) { + } $timeout(_, NEXT_TICK); }); } } + _(); } } @@ -622,7 +632,7 @@ angular.module('web') Bucket: bucket, Key: newKey, CopySource: '/' + bucket + '/' + encodeURIComponent(oldKey), - MetadataDirective: 'REPLACE' // 'REPLACE' 表示覆盖 meta 信息,'COPY' 表示不覆盖,只拷贝 + MetadataDirective: 'COPY' // 'REPLACE' 表示覆盖 meta 信息,'COPY' 表示不覆盖,只拷贝, }, function (err) { if (err) { df.reject(err); @@ -691,6 +701,7 @@ angular.module('web') } }); } + dig({}); return df.promise; } @@ -721,6 +732,7 @@ angular.module('web') } }); } + dig(); return df.promise; } @@ -949,7 +961,6 @@ angular.module('web') 'ContentEncoding': '', 'Expires': result.Expires, 'Metadata': result.Metadata - }, function (err) { if (err) { handleError(err); @@ -1037,9 +1048,9 @@ angular.module('web') ContentType: headers['ContentType'], CacheControl: headers['CacheControl'], ContentDisposition: headers['ContentDisposition'], - ContentEncoding: '', //headers['ContentEncoding'], + ContentEncoding: headers['ContentEncoding'], ContentLanguage: headers['ContentLanguage'], - Expires: headers['Expires'], + Expires: headers['Expires'] }; client.copyObject(opt, function (err, data) { @@ -1417,10 +1428,9 @@ angular.module('web') bucket = opt.bucket; } } - - var endpoint = getOssEndpoint(authInfo.region || 'oss-cn-beijing', bucket, authInfo.eptpl); + var endpointname = authInfo.cname ? authInfo.eptplcname : authInfo.eptpl; + var endpoint = getOssEndpoint(authInfo.region || 'oss-cn-beijing', bucket, endpointname); console.log("[endpoint]:", endpoint) - var options = { //region: authInfo.region, accessKeyId: authInfo.id || 'a', @@ -1430,7 +1440,9 @@ angular.module('web') httpOptions: { timeout: authInfo.httpOptions ? authInfo.httpOptions.timeout : 0 }, - maxRetries: 50 + maxRetries: 50, + cname: authInfo.cname || false, + isRequestPayer: authInfo.requestpaystatus == 'NO' ? false : true }; if (authInfo.id && authInfo.id.indexOf('STS.') == 0) { diff --git a/app/components/services/settings.js b/app/components/services/settings.js index c6081e01..429b782a 100644 --- a/app/components/services/settings.js +++ b/app/components/services/settings.js @@ -1,57 +1,113 @@ angular.module('web') -.factory('settingsSvs', [function(){ + .factory('settingsSvs', [function () { - return { - autoUpgrade: { - get: function(){ - return parseInt(localStorage.getItem('autoUpgrade')||1); + return { + autoUpgrade: { + get: function () { + return parseInt(localStorage.getItem('autoUpgrade') || 1); + }, + set: function (v) { + return localStorage.setItem('autoUpgrade', v); + } }, - set: function(v){ - return localStorage.setItem('autoUpgrade',v); - } - }, - maxUploadJobCount: { - get: function(){ - return parseInt(localStorage.getItem('maxUploadJobCount')||3); + isCame: { + get: function () { + return parseInt(localStorage.getItem('isCame') || 0); + }, + set: function (v) { + return localStorage.setItem('isCame', v); + } + }, + maxUploadJobCount: { + get: function () { + return parseInt(localStorage.getItem('maxUploadJobCount') || 3); + }, + set: function (v) { + return localStorage.setItem('maxUploadJobCount', v); + } }, - set: function(v){ - return localStorage.setItem('maxUploadJobCount',v); - } - }, - maxDownloadJobCount: { - get: function(){ - return parseInt(localStorage.getItem('maxDownloadJobCount')||3); + maxDownloadJobCount: { + get: function () { + return parseInt(localStorage.getItem('maxDownloadJobCount') || 3); + }, + set: function (v) { + return localStorage.setItem('maxDownloadJobCount', v); + } }, - set: function(v){ - return localStorage.setItem('maxDownloadJobCount',v); - } - }, - showImageSnapshot: { - get: function(){ - return parseInt(localStorage.getItem('showImageSnapshot')||1); + showImageSnapshot: { + get: function () { + return parseInt(localStorage.getItem('showImageSnapshot') || 1); + }, + set: function (v) { + return localStorage.setItem('showImageSnapshot', v); + } }, - set: function(v){ - return localStorage.setItem('showImageSnapshot',v); - } - }, - historiesLength: { - get: function(){ - return parseInt(localStorage.getItem('historiesLength')||100); + historiesLength: { + get: function () { + return parseInt(localStorage.getItem('historiesLength') || 100); + }, + set: function (v) { + return localStorage.setItem('historiesLength', v); + } }, - set: function(v){ - return localStorage.setItem('historiesLength',v); - } - }, - mailSmtp: { - get: function(){ - return JSON.parse(localStorage.getItem('mailSender')||'{"port":465}'); + mailSmtp: { + get: function () { + return JSON.parse(localStorage.getItem('mailSender') || '{"port":465}'); + }, + set: function (v) { + return localStorage.setItem('mailSender', JSON.stringify(v)); + } + }, + logFile: { + get: function () { + return parseInt(localStorage.getItem('logFile') || 0); + }, + set: function (v) { + return localStorage.setItem('logFile', v); + } + }, + logFileInfo: { + get: function () { + return parseInt(localStorage.getItem('logFileInfo') || 0); + }, + set: function (v) { + return localStorage.setItem('logFileInfo', v); + } + }, + getRequestPayStatus: { + get: function () { + return localStorage.getItem('show-request-pay') || 'NO'; + }, + set: function (v) { + return localStorage.setItem('show-request-pay', v); + } + }, + connectTimeout: { + get: function () { + return parseInt(localStorage.getItem('connectTimeout') || 60000); + }, + set: function (v) { + return localStorage.setItem('connectTimeout', v); + } + }, + uploadPartSize: { + get: function () { + return parseInt(localStorage.getItem('uploadPartSize') || 10); + }, + set: function (v) { + return localStorage.setItem('uploadPartSize', v); + } }, - set: function(v){ - return localStorage.setItem('mailSender',JSON.stringify(v)); + uploadAndDownloadRetryTimes: { + get: function () { + return parseInt(localStorage.getItem('uploadAndDownloadRetryTimes') || 10); + }, + set: function (v) { + return localStorage.setItem('uploadAndDownloadRetryTimes', v); + } } - } - }; -}]); + }; + }]); diff --git a/app/const.js b/app/const.js index 8e21cbe2..b9051cb1 100644 --- a/app/const.js +++ b/app/const.js @@ -33,6 +33,20 @@ angular.module('web') AUTH_KEEP: 'auth-keep', KEY_REMEMBER: 'auth-remember', SHOW_HIS: 'show-his', + SHOW_REQUEST_PAY: 'show-request-pay', + + IMM_DOC_PREVIEW_LINK: 'https://help.aliyun.com/', + IMM_DOC_TYPES: [ + //演示文件: + // 'pptx','ppt','pot','potx','pps','ppsx','dps','dpt','pptm','potm','ppsm', + // //表格文件: + // 'xls','xlt','et','ett','xlsx','xltx','csv','xlsb','xlsm','xltm', + // //文字文件: + // 'doc','dot','wps','wpt','docx','dotx','docm','dotm', + //其他格式文件: + 'pdf', + //'lrc','c','cpp','h','asm','s','java','asp','bat','bas','prg','cmd','rtf','txt','log','xml','htm','html', + ], REG: { EMAIL: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/ @@ -88,6 +102,11 @@ angular.module('web') label: '华南1(深圳)', storageClasses: getStorageClasses(3) }, + { + id: 'oss-cn-chengdu', + label: '西南1(成都)', + storageClasses: getStorageClasses(3) + }, { id: 'oss-cn-hongkong', label: '香港', @@ -145,6 +164,11 @@ angular.module('web') label: '中东东部1(迪拜)', storageClasses: getStorageClasses(3) }, + { + id: 'oss-eu-west-1', + label: '英国(伦敦)', + storageClasses: getStorageClasses(3) + } ], countryNum: [{ diff --git a/app/index.html b/app/index.html index 37698e14..d6e83ef1 100644 --- a/app/index.html +++ b/app/index.html @@ -5,15 +5,15 @@ OSS Browser + +
-
- -
-
- -
- - +
+ +
+
+ + +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
-
+
- -
- -
- -
- -
-
- -
- - -
-
-
- -
- -
-
-
- -
- -
-
- -
- -
- -
-
- - -
-
- -
-
- - -
-
- +
+ +
+ +
+
+
+ +
+
-
-
+
+ +
+
+
+
- - - - - - - - - - -
-IDSecret{{'auth.description'|translate}}{{'actions'|translate}}
{{$index+1}}{{h.id}}{{h.secret|hideSecret}}{{h.desc}} - {{'use'|translate}} | - {{'delete'|translate}} -
+ +
+
+ + + + +
+
+ + + +
+ +
+ +
+ + + + + {{'auth.authToken.error.invalid'|translate}} + + + + {{'auth.authToken.error.expired'|translate}} + + + + ({{"auth.authToken.info.validUntil"|translate:{expiration:authTokenInfo.expirationStr} + }}, + + {{'auth.authToken.info.leftTime'|translate}}: + + ) + +
+
+ +
+
+ + +
+
+
+ + +
-
+
+ +
+ + +
+
+

+ {{'auth.akHistories'|translate}} + +

+ +
+ + + + + + + + + + + + + + + +
-IDSecret{{'auth.description'|translate}}{{'actions'|translate}}
{{$index+1}}{{h.id}}{{h.secret|hideSecret}}{{h.desc}} + {{'use'|translate}} | + {{'delete'|translate}} +
+
+
diff --git a/app/main/auth/login.js b/app/main/auth/login.js index 13cc1562..d730debc 100644 --- a/app/main/auth/login.js +++ b/app/main/auth/login.js @@ -1,22 +1,23 @@ - angular.module('web') - .controller('loginCtrl', ['$scope', '$rootScope', '$translate','Auth','AuthInfo','$timeout','$location','Const','Dialog','Toast','Cipher', - function ($scope, $rootScope, $translate, Auth, AuthInfo,$timeout, $location, Const, Dialog, Toast, Cipher) { + .controller('loginCtrl', ['$scope', '$rootScope', '$translate', 'Auth', 'AuthInfo', '$timeout', '$location', 'Const', 'Dialog', 'Toast', 'Cipher', 'settingsSvs', + function ($scope, $rootScope, $translate, Auth, AuthInfo, $timeout, $location, Const, Dialog, Toast, Cipher, settingsSvs) { var DEF_EP_TPL = 'https://{region}.aliyuncs.com/'; var KEY_REMEMBER = Const.KEY_REMEMBER; var SHOW_HIS = Const.SHOW_HIS; + var SHOW_REQUEST_PAY = Const.SHOW_REQUEST_PAY; var KEY_AUTHTOKEN = 'key-authtoken'; var regions = angular.copy(Const.regions); var T = $translate.instant; angular.extend($scope, { - gtab: parseInt(localStorage.getItem('gtag')||1), + gtab: parseInt(localStorage.getItem('gtag') || 1), flags: { remember: 'NO', - showHis: 'NO' + showHis: 'NO', + requestpaystatus: 'NO' }, item: { eptpl: DEF_EP_TPL, @@ -34,82 +35,103 @@ angular.module('web') open: open, onSubmit2: onSubmit2, - authTokenChange:authTokenChange, + authTokenChange: authTokenChange, - eptplChange: eptplChange + eptplChange: eptplChange, }); - $scope.$watch('item.eptpl', function(v){ - $scope.eptplType = (v==DEF_EP_TPL)?'default':'customize'; + $scope.$watch('item.eptpl', function (v) { + $scope.eptplType = (v == DEF_EP_TPL) ? 'default' : 'customize'; }); - $scope.$watch('gtab', function(v){ - localStorage.setItem('gtag',v) + + // $scope.$watch('item.eptpl', function(v){ + // // $scope.eptplType = (v==DEF_EP_TPL)?'default':'customize'; + // }); + + $scope.$watch('gtab', function (v) { + localStorage.setItem('gtag', v) }); + $scope.$watch('item.cname', function (v) { + console.log('cname: ' + v) + if (v) { + $scope.eptplType = 'cname' + } + }); - function eptplChange(t){ - $scope.eptplType=t; + function eptplChange(t) { + $scope.eptplType = t; //console.log(t); - if(t=='default'){ - $scope.item.eptpl = DEF_EP_TPL; - }else{ - $scope.item.eptpl =''; + if (t == 'default') { + $scope.item.eptpl = DEF_EP_TPL; + $scope.item.cname = false; + } else if (t == 'customize') { + $scope.item.cname = false; + $scope.item.eptpl = ''; + } else if (t == 'cname') { + $scope.item.cname = true; + $scope.item.eptplcname = ''; } } - function open(a){ + function open(a) { openExternal(a); } var tid; - function authTokenChange(){ + + function authTokenChange() { $timeout.cancel(tid); - tid=$timeout(function(){ - var authToken = $scope.item.authToken||''; + tid = $timeout(function () { + var authToken = $scope.item.authToken || ''; localStorage.setItem(KEY_AUTHTOKEN, authToken); - if(!authToken){ + if (!authToken) { $scope.authTokenInfo = null; return; } - try{ + try { var str = Buffer.from(authToken, 'base64').toString(); var info = JSON.parse(str); - if(info.id && info.secret && info.stoken && info.privilege && info.expiration && info.osspath){ + if (info.id && info.secret && info.stoken && info.privilege && info.expiration && info.osspath) { - //过期 - try{ - var d = new Date(info.expiration).getTime(); - info.isExpired = d <= new Date().getTime(); - }catch(e){ + //过期 + try { + var d = new Date(info.expiration).getTime(); + info.isExpired = d <= new Date().getTime(); + } catch (e) { - } - $scope.authTokenInfo = info; + } + $scope.authTokenInfo = info; - $scope.authTokenInfo.expirationStr = moment(new Date(info.expiration)).format('YYYY-MM-DD HH:mm:ss'); + $scope.authTokenInfo.expirationStr = moment(new Date(info.expiration)).format('YYYY-MM-DD HH:mm:ss'); } - else if(info.id && info.secret && !info.id.startsWith('STS.')){ + else if (info.id && info.secret && !info.id.startsWith('STS.')) { //子用户ak $scope.authTokenInfo = info; } - else if(new Date(info.expiration).getTime() < new Date().getTime()){ - $scope.authTokenInfo = null; + else if (new Date(info.expiration).getTime() < new Date().getTime()) { + $scope.authTokenInfo = null; } - }catch(e){ - $scope.authTokenInfo = null; + } catch (e) { + $scope.authTokenInfo = null; } - },600); + }, 600); } init(); - function init(){ + + function init() { $scope.flags.remember = localStorage.getItem(KEY_REMEMBER) || 'NO'; $scope.flags.showHis = localStorage.getItem(SHOW_HIS) || 'NO'; - angular.extend($scope.item , AuthInfo.getRemember()); + + //requestPay状态 + $scope.flags.requestpaystatus = localStorage.getItem(SHOW_REQUEST_PAY) || 'NO'; + angular.extend($scope.item, AuthInfo.getRemember()); //临时token @@ -118,79 +140,88 @@ angular.module('web') listHistories(); - $scope.$watch('flags.remember',function(v){ - if(v=='NO'){ + $scope.$watch('flags.remember', function (v) { + if (v == 'NO') { AuthInfo.unremember(); - localStorage.setItem(KEY_REMEMBER,'NO'); + localStorage.setItem(KEY_REMEMBER, 'NO'); } }); - $scope.$watch('flags.showHis',function(v){ - localStorage.setItem(SHOW_HIS,v); + $scope.$watch('flags.showHis', function (v) { + localStorage.setItem(SHOW_HIS, v); + }); + + $scope.$watch('flags.requestpaystatus', function (v) { + console.log(v) + localStorage.setItem(SHOW_REQUEST_PAY, v); }); } - function useHis(h){ + function useHis(h) { + if (h.cname) { + $scope.eptplType = 'cname' + } angular.extend($scope.item, h); + $scope.item.desc = h.desc || ''; } - function showRemoveHis(h){ + function showRemoveHis(h) { var title = T('auth.removeAK.title'); //删除AK - var message = T('auth.removeAK.message',{id: h.id}); //'ID:'+h.id+', 确定删除?' - Dialog.confirm(title,message,function(b){ - if(b){ + var message = T('auth.removeAK.message', {id: h.id}); //'ID:'+h.id+', 确定删除?' + Dialog.confirm(title, message, function (b) { + if (b) { AuthInfo.removeFromHistories(h.id); listHistories(); } - },1); + }, 1); } - function listHistories(){ + function listHistories() { $scope.his = AuthInfo.listHistories(); } - function showCleanHistories(){ + function showCleanHistories() { var title = T('auth.clearAKHistories.title'); //清空AK历史 var message = T('auth.clearAKHistories.message'); //确定? var successMessage = T('auth.clearAKHistories.successMessage'); //已清空AK历史 - Dialog.confirm(title, message,function(b){ - if(b){ + Dialog.confirm(title, message, function (b) { + if (b) { AuthInfo.cleanHistories(); listHistories(); Toast.success(successMessage); } - },1); + }, 1); } + function onSubmit(form1) { + if (!form1.$valid) return; + localStorage.setItem(KEY_REMEMBER, $scope.flags.remember); + var data = angular.copy($scope.item); - function onSubmit(form1){ - - if(!form1.$valid)return; - - localStorage.setItem(KEY_REMEMBER,$scope.flags.remember); + delete data.requestpaystatus; - var data = angular.copy($scope.item); + if (!data.requestpaystatus) { + data.requestpaystatus = localStorage.getItem(SHOW_REQUEST_PAY) || 'NO'; + } //trim password - if(data.secret) data.secret = data.secret.trim(); + if (data.secret) data.secret = data.secret.trim(); delete data.authToken; delete data.securityToken; - if(data.id.indexOf('STS.')!=0){ + if (data.id.indexOf('STS.') != 0) { delete data.stoken; } - if($scope.flags.remember=='YES'){ + if ($scope.flags.remember == 'YES') { AuthInfo.remember(data); } Toast.info(T('logining'), 1000); - - - Auth.login(data).then(function(){ + Auth.login(data).then(function () { if (!data.region && data.eptpl.indexOf('{region}') === -1) { var regExp = /https?:\/\/(\S*)\.aliyuncs\.com/; var res = data.eptpl.match(regExp); @@ -200,23 +231,23 @@ angular.module('web') AuthInfo.save(data); } } - if($scope.flags.remember=='YES') AuthInfo.addToHistories(data); + if ($scope.flags.remember == 'YES') AuthInfo.addToHistories(data); Toast.success(T('login.successfully'), 1000); $location.url('https://github.com/'); - },function(err){ - Toast.error(err.code+':'+err.message); + }, function (err) { + Toast.error(err.code + ':' + err.message); }); return false; } //token login - function onSubmit2(form2){ + function onSubmit2(form2) { - if(!form2.$valid)return; + if (!form2.$valid) return; - if(!$scope.authTokenInfo){ + if (!$scope.authTokenInfo) { return; } @@ -224,11 +255,11 @@ angular.module('web') Toast.info(T('logining'), 1000);//'正在登录...' - Auth.login(data).then(function(){ + Auth.login(data).then(function () { Toast.success(T('login.successfully'), 1000);//'登录成功,正在跳转...' $location.url('https://github.com/'); - },function(err){ - Toast.error(err.code+':'+err.message); + }, function (err) { + Toast.error(err.code + ':' + err.message); }); return false; diff --git a/app/main/files/_/batch-restore-modal.js b/app/main/files/_/batch-restore-modal.js new file mode 100644 index 00000000..bcbe2700 --- /dev/null +++ b/app/main/files/_/batch-restore-modal.js @@ -0,0 +1,64 @@ +angular.module('web') + .controller('batchRestoreModalCtrl', ['$scope','$uibModalInstance','$translate','ossSvs2','item','currentInfo','callback','Toast','safeApply', + function($scope, $modalInstance, $translate, ossSvs2, items, currentInfo, callback, Toast, safeApply) { + var T = $translate.instant; + angular.extend($scope, { + currentInfo: currentInfo, + items: items, + info: { + days: 1, + msg: null + }, + cancel: cancel, + onSubmit: onSubmit + }); + + init(); + function init() { + $scope.isLoading = true; + for(let i in items){ + ossSvs2.getFileInfo(currentInfo.region, currentInfo.bucket, items[i].path).then(function(data){ + if(data.Restore){ + var info = parseRestoreInfo(data.Restore); + if(info['ongoing-request'] == 'true') { + $scope.info.type = 2; + } else { + $scope.info.type = 3; + $scope.inf.expiry_date = info['expiry-date']; + } + } else { + $scope.info.type = 1; + } + $scope.isLoading = false; + safeApply($scope); + }); + } + }; + + function parseRestoreInfo(s) { + var arr = s.match(/([\w\-]+)=\"([^\"]+)\"/g); + var m = {}; + angular.forEach(arr, function(n) { + var kv = n.match(/([\w\-]+)=\"([^\"]+)\"/); + m[kv[1]] = kv[2]; + }); + return m; + }; + + function cancel() { + $modalInstance.dismiss('close'); + }; + + function onSubmit(form1) { + if(!form1.$valid)return; + var days = $scope.info.days; + Toast.info(T('restore.on'));//'提交中...' + for(let i in items){ + ossSvs2.restoreFile(currentInfo.region, currentInfo.bucket, items[i].path, days).then(function() { + callback(); + cancel(); + }); + } + Toast.success(T('restore.success'));//'恢复请求已经提交' + }; + }]); \ No newline at end of file diff --git a/app/main/files/_/file-toolbar.html b/app/main/files/_/file-toolbar.html index 0cc7447b..8e085b3d 100644 --- a/app/main/files/_/file-toolbar.html +++ b/app/main/files/_/file-toolbar.html @@ -66,7 +66,8 @@
- - -
+
{{'cannot.preview'|translate}}
diff --git a/app/main/files/modals/preview/picture-modal.js b/app/main/files/modals/preview/picture-modal.js index 212dd0ec..18d3e828 100644 --- a/app/main/files/modals/preview/picture-modal.js +++ b/app/main/files/modals/preview/picture-modal.js @@ -1,7 +1,7 @@ angular.module('web') .controller('pictureModalCtrl', ['$scope', '$uibModalInstance', '$timeout', '$uibModal', 'ossSvs2', 'safeApply', 'showFn', 'bucketInfo', 'objectInfo','AuthInfo', 'fileType', function ($scope, $modalInstance, $timeout, $modal, ossSvs2, safeApply, showFn, bucketInfo, objectInfo, AuthInfo, fileType) { - + angular.extend($scope, { bucketInfo: bucketInfo, objectInfo: objectInfo, @@ -22,9 +22,7 @@ angular.module('web') function afterCheckSuccess() { $scope.previewBarVisible = true; - if (objectInfo.size < $scope.MAX_SIZE) { - getContent(); - } + getContent(); } function cancel() { @@ -41,14 +39,19 @@ angular.module('web') } }) } - else{ + else { + var process = "image/quality,q_10"; var url = ossSvs2.signatureUrl(bucketInfo.region, bucketInfo.bucket, objectInfo.path); + var url5M = ossSvs2.signatureUrl2(bucketInfo.region, bucketInfo.bucket, objectInfo.path, 3600, process); $timeout(function () { - $scope.imgsrc = url; + if (objectInfo.size < $scope.MAX_SIZE) { + $scope.imgsrc = url; + } else { + $scope.imgsrc = url5M; + } }, 300); } } - } ]); diff --git a/app/main/files/transfer/downloads.html b/app/main/files/transfer/downloads.html index f956887d..ebedbf44 100644 --- a/app/main/files/transfer/downloads.html +++ b/app/main/files/transfer/downloads.html @@ -69,6 +69,10 @@ {{item.speed|sizeFormat}}/s + + + {{retryTimes}} +
@@ -78,7 +82,7 @@
- diff --git a/app/main/files/transfer/downloads.js b/app/main/files/transfer/downloads.js index 489b4bdb..8a4bc5ea 100644 --- a/app/main/files/transfer/downloads.js +++ b/app/main/files/transfer/downloads.js @@ -89,7 +89,7 @@ angular.module('web') var arr = $scope.lists.downloadJobList; for (var i = 0; i < arr.length; i++) { var n = arr[i]; - if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying') n.stop(); + if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying' || n.status == 'retrying') n.stop(); arr.splice(i, 1); i--; } @@ -112,7 +112,7 @@ angular.module('web') $scope.allActionBtnDisabled = true; angular.forEach(arr, function (n) { - if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying') n.stop(); + if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying' || n.status == 'retrying') n.stop(); }); Toast.success(T('pause.success')); //'暂停成功' diff --git a/app/main/files/transfer/uploads.html b/app/main/files/transfer/uploads.html index 1c61e441..1d018359 100644 --- a/app/main/files/transfer/uploads.html +++ b/app/main/files/transfer/uploads.html @@ -67,6 +67,9 @@ {{item.speed|sizeFormat}}/s + + {{retryTimes}} +
@@ -76,7 +79,7 @@
- diff --git a/app/main/files/transfer/uploads.js b/app/main/files/transfer/uploads.js index 5f7f0e83..3641eec8 100644 --- a/app/main/files/transfer/uploads.js +++ b/app/main/files/transfer/uploads.js @@ -83,7 +83,7 @@ angular.module('web') var arr = $scope.lists.uploadJobList; for (var i = 0; i < arr.length; i++) { var n = arr[i]; - if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying') n.stop(); + if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying' || n.status == 'retrying') n.stop(); arr.splice(i, 1); i--; } @@ -106,7 +106,7 @@ angular.module('web') $scope.allActionBtnDisabled=true; angular.forEach(arr, function (n) { - if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying') n.stop(); + if (n.status == 'running' || n.status == 'waiting'|| n.status == 'verifying' || n.status == 'retrying') n.stop(); }); Toast.info(T('pause.success')); diff --git a/app/main/modals/settings.html b/app/main/modals/settings.html index 3d19ccf7..87a76666 100644 --- a/app/main/modals/settings.html +++ b/app/main/modals/settings.html @@ -33,6 +33,36 @@
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + {{'settings.console'|translate}}: + +
+ +
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ +
+
+
+ + +