Compare commits

...

12 Commits
0.7.1 ... 0.9

Author SHA1 Message Date
zhaojun1998
4c914793b0 📝 更新文档 2020-01-29 13:43:19 +08:00
zhaojun1998
5698cfb2d3 🔖 发布 0.9 版 2020-01-29 13:41:42 +08:00
zhaojun1998
3cd5f8f9a7 调整显示顺序 2020-01-29 12:58:03 +08:00
zhaojun1998
76747771de OneDrive 世纪互联支持 2020-01-29 12:53:38 +08:00
zhaojun1998
cfacd39210 优化代码, 增强健壮性 2020-01-29 12:52:07 +08:00
zhaojun1998
90cd13f2c3 🔖 发布 0.8 版 2020-01-28 15:19:04 +08:00
zhaojun1998
018a68246e 💄 更新页面 2020-01-28 15:16:27 +08:00
zhaojun1998
b6a2e3ccb8 添加获取指定路径文件信息的 API 2020-01-28 14:55:06 +08:00
zhaojun1998
38b811f8e6 🐛 新增 '搜索包含加密文件' 支持. 2020-01-28 13:25:28 +08:00
zhaojun1998
6922fa2195 添加自定义 JS, CSS 支持 2020-01-28 13:14:23 +08:00
zhaojun1998
4bca6cf7a5 移除尾部说明文件支持 2020-01-28 13:13:52 +08:00
zhaojun1998
c3484426ab 🐛 修复 OneDrive 教育版和部分国际版无法正常获取文件的 BUG 2020-01-28 10:18:36 +08:00
33 changed files with 581 additions and 162 deletions

View File

@@ -16,46 +16,74 @@
* 内存缓存 (免安装)
* 内存数据库 (免安装)
* 个性化配置
* 自定义目录的 header 和 footer 说明文件
* 自定义目录的 header 说明文件
* 自定义 JS, CSS
* 文件夹密码
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
* 文件/目录二维码
* 缓存动态开启, 缓存自动刷新
* 全局搜索
* 支持 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版, OneDrive 世纪互联版, 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
## 快速开始
安装 JDK 1.8 :
安装依赖环境:
```bash
yum install -y java # 适用于 Centos 7.x
# CentOS系统
yum install -y java-1.8.0-openjdk unzip
# Debian/Ubuntu系统
apt update
apt install -y default-jdk unzip
```
下载项目:
```bash
wget https://github.com/zhaojun1998/zfile/releases/download/0.7.1/zfile-0.7.1.jar
wget -P ~ https://c.jun6.net/ZFILE/zfile-0.9.war
cd ~
mkdir zfile && unzip zfile-0.9.war -d zfile && rm -rf zfile-0.9.war
chmod +x ~/zfile/bin/*.sh
```
程序的目录结构为:
```
├── zfile
├── META-INF
├── WEB-INF
└── bin
├── start.sh # 启动脚本
└── stop.sh # 停止脚本
├── restart.sh # 重启脚本
```
启动项目:
```bash
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar
## 高级启动
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar --server.port=18777
## 后台运行
nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar &
~/zfile/bin/start.sh
```
> 系统使用的是内置配置文件, 默认配置请参考: [application.yml](https://github.com/zhaojun1998/zfile/blob/master/src/main/resources/application.yml)
停止项目:
> **可下载此文件放置与 jar 包同目录, 此时会以外部配置文件为准, 推荐适用此方式!.**
```bash
~/zfile/bin/stop.sh
```
> 所有参数都可在命令行启动时, 以类似 `--server.port=18777` 的方式强制执行, 此方式的优先级最高.
重启项目:
> *指定 `-Djava.security.egd=file:/dev/./urandom` 是为了防止在 Linux 环境中, 生成首次登陆生成 sessionId 取系统随机数过慢的问题.*
```bash
~/zfile/bin/restart.sh
```
修改配置文件:
```bash
vim ~/zfile/WEB-INF/classes/application.yml
```
> 默认启动端口为 8080, 如需请配置文件请编辑上述文件, 修改后重启程序生效.
访问地址:
@@ -68,7 +96,18 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar &
## OneDrive 使用教程.
访问地址进行授权, 获取 accessToken 和 refreshToken: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=09939809-c617-43c8-a220-a93c1513c5d4&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
访问地址进行授权, 获取 accessToken 和 refreshToken:
国际/家庭/个人版:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=09939809-c617-43c8-a220-a93c1513c5d4&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
世纪互联版:
https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?client_id=4a72d927-1907-488d-9eb2-1b465c53c1c5&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/china-callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
然后分别填写至访问令牌和刷新令牌即可:
@@ -93,7 +132,6 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar &
### 头尾文件和加密文件
- 目录头部显示文件名为 `header.md`
- 目录底部显示文件名为 `footer.md`
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
## TODO
@@ -109,5 +147,5 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.1.jar &
如果本项目对你有帮助,请作者喝杯咖啡吧。
<img src="http://cdn.jun6.net/alipay.png" width="150" height="234">
<img src="http://cdn.jun6.net/alipay.png" width="200" height="312">
<img src="http://cdn.jun6.net/wechat.png" width="222" height="300">

23
pom.xml
View File

@@ -12,8 +12,9 @@
<groupId>im.zhaojun</groupId>
<artifactId>zfile</artifactId>
<version>0.7.1</version>
<version>0.9</version>
<name>zfile</name>
<packaging>war</packaging>
<description>一个在线的文件浏览系统</description>
<properties>
@@ -132,6 +133,26 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.uyoqu.framework</groupId>
<artifactId>maven-plugin-starter</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>bin</goal>
</goals>
</execution>
</executions>
<configuration>
<jvms>
<jvm>-server</jvm>
<jvm>-Xmx512m</jvm>
<jvm>-Djava.security.egd=file:/dev/./urandom</jvm>
</jvms>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -6,9 +6,11 @@ import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import im.zhaojun.onedrive.service.OneDriveService;
import im.zhaojun.onedrive.service.OneDriveServiceImpl;
import im.zhaojun.onedrive.service.OneDriveToken;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.china.service.OneDriveServiceChinaImpl;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import im.zhaojun.onedrive.international.service.OneDriveService;
import im.zhaojun.onedrive.international.service.OneDriveServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -17,6 +19,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
/**
* @author zhaojun
@@ -32,6 +35,9 @@ public class GlobalScheduleTask {
@Resource
private OneDriveService oneDriveService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@Resource
private SystemConfigService systemConfigService;
@@ -43,7 +49,8 @@ public class GlobalScheduleTask {
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
if (!(currentFileService instanceof OneDriveServiceImpl)) {
if (!(currentFileService instanceof OneDriveServiceImpl
|| currentFileService instanceof OneDriveServiceChinaImpl)) {
log.debug("当前启用存储类型, 不是 OneDrive, 跳过自动刷新 AccessToken");
return;
}
@@ -53,23 +60,44 @@ public class GlobalScheduleTask {
return;
}
refreshOneDriveToken();
try {
refreshOneDriveToken(StorageTypeEnum.ONE_DRIVE);
} catch (Exception e) {
log.debug("刷新 OneDrive Token 失败.", e);
}
try {
refreshOneDriveToken(StorageTypeEnum.ONE_DRIVE_CHINA);
} catch (Exception e) {
log.debug("刷新 OneDrive 世纪互联 Token 失败.", e);
}
}
/**
* 调用刷新 OneDrive Token
*/
public void refreshOneDriveToken() {
OneDriveToken refreshToken = oneDriveService.getRefreshToken();
public void refreshOneDriveToken(StorageTypeEnum storageType) {
OneDriveToken refreshToken;
if (Objects.equals(storageType, StorageTypeEnum.ONE_DRIVE_CHINA)) {
refreshToken = oneDriveChinaService.getRefreshToken();
} else {
refreshToken = oneDriveService.getRefreshToken();
}
if (refreshToken.getAccessToken() == null || refreshToken.getRefreshToken() == null) {
return;
}
StorageConfig accessTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.ACCESS_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.ACCESS_TOKEN_KEY);
StorageConfig refreshTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.REFRESH_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.REFRESH_TOKEN_KEY);
accessTokenConfig.setValue(refreshToken.getAccessToken());
refreshTokenConfig.setValue(refreshToken.getRefreshToken());
storageConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig));
log.info("刷新 OneDrive key 时间: " + LocalDateTime.now());
log.info("刷新 {} key 时间: {}", storageType.getDescription(), LocalDateTime.now());
}
}

View File

@@ -63,7 +63,9 @@ public class AdminController {
StorageTypeEnum currentStorageStrategy = currentFileService.getStorageTypeEnum();
if (!Objects.equals(currentStorageStrategy, systemConfigDTO.getStorageStrategy())) {
log.info("已将存储策略由 {} 切换为 {}", currentStorageStrategy, systemConfigDTO.getStorageStrategy());
log.info("已将存储策略由 {} 切换为 {}",
currentStorageStrategy.getDescription(),
systemConfigDTO.getStorageStrategy().getDescription());
refreshStorageStrategy();
}

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.controller;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.annotation.CheckStorageStrategyInit;
import im.zhaojun.common.exception.SearchDisableException;
@@ -88,10 +89,10 @@ public class FileController {
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String order,
@RequestParam(defaultValue = "1") Integer page) throws Exception {
@RequestParam(defaultValue = "1") Integer page) {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
if (!systemConfigDTO.getSearchEnable()) {
if (BooleanUtil.isFalse(systemConfigDTO.getSearchEnable())) {
throw new SearchDisableException("搜索功能未开启");
}
if (!fileAsyncCacheService.isCacheFinish()) {
@@ -112,7 +113,6 @@ public class FileController {
}
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.FOOTER_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.HEADER_FILE_NAME.equals(fileItem.getName()));
}
@@ -134,4 +134,17 @@ public class FileController {
end = Math.min(end, total);
return new ArrayList<>(fileItemList.subList(start, end));
}
/**
* 获取指定路径下的文件信息内容
* @param path 文件全路径
* @return 该文件的名称, 路径, 大小, 下载地址等信息.
*/
@CheckStorageStrategyInit
@GetMapping("/directlink")
public ResultBean directlink(String path) {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
return ResultBean.successData(fileService.getFileItem(path));
}
}

View File

@@ -46,9 +46,9 @@ public class GlobleExceptionHandler {
* 不存在的文件异常
*/
@ExceptionHandler({NotExistFileException.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public String notExistFile(Exception ex) {
return "error/404";
@ResponseBody
public ResultBean notExistFile(Exception ex) {
return ResultBean.error("文件不存在");
}
/**

View File

@@ -19,11 +19,6 @@ public class ZFileConstant {
*/
public static String HEADER_FILE_NAME = "header.md";
/**
* 页面尾部文件
*/
public static String FOOTER_FILE_NAME = "footer.md";
/**
* 密码文件
*/
@@ -34,11 +29,6 @@ public class ZFileConstant {
ZFileConstant.HEADER_FILE_NAME = headerFileName;
}
@Autowired(required = false)
public void setFooterFileName(@Value("${zfile.constant.footer}") String footerFileName) {
ZFileConstant.FOOTER_FILE_NAME = footerFileName;
}
@Autowired(required = false)
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;

View File

@@ -1,53 +1,23 @@
package im.zhaojun.common.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* @author zhaojun
*/
@Data
@ToString
public class SiteConfigDTO implements Serializable {
private static final long serialVersionUID = 8811196207046121740L;
private String header;
private String footer;
@JsonProperty("viewConfig")
private SystemConfigDTO systemConfigDTO;
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getFooter() {
return footer;
}
public void setFooter(String footer) {
this.footer = footer;
}
public SystemConfigDTO getSystemConfigDTO() {
return systemConfigDTO;
}
public void setSystemConfigDTO(SystemConfigDTO systemConfigDTO) {
this.systemConfigDTO = systemConfigDTO;
}
@Override
public String toString() {
return "SiteConfigDTO{" +
"header='" + header + '\'' +
", footer='" + footer + '\'' +
", systemConfig=" + systemConfigDTO +
'}';
}
}

View File

@@ -37,4 +37,11 @@ public class SystemConfigDTO {
private String domain;
private Boolean enableCache;
private Boolean searchContainEncryptedFile;
private String customJs;
private String customCss;
}

View File

@@ -20,10 +20,12 @@ public enum StorageTypeEnum {
LOCAL("local", "本地存储"),
MINIO("minio", "MINIO"),
ONE_DRIVE("onedrive", "OneDrive"),
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
QINIU("qiniu", "七牛云 KODO"),
TENCENT("tencent", "腾讯云 COS"),
UPYUN("upyun", "又拍云 USS");
private String key;
private String description;

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.service;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.RefreshPolicy;
@@ -7,7 +8,9 @@ import com.alicp.jetcache.anno.CacheRefresh;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.alicp.jetcache.anno.CreateCache;
import im.zhaojun.common.model.constant.ZFileConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.util.StringUtils;
@@ -21,6 +24,7 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -119,9 +123,8 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
* 搜索文件
* @param name 文件名
* @return 包含该文件名的所有文件或文件夹
* @throws Exception 搜索过程出现的异常
*/
public List<FileItemDTO> search(String name) throws Exception {
public List<FileItemDTO> search(String name) {
List<FileItemDTO> result = new ArrayList<>();
boolean searchIgnoreCase = systemConfigService.getSearchIgnoreCase();
@@ -168,7 +171,7 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
List<FileItemDTO> cacheList = cache.get(filePath);
if (cacheList != null) {
if (cacheList != null && isNotEncryptedFolder(cacheList)) {
queue.addAll(cacheList);
}
}
@@ -177,12 +180,32 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
return result;
}
/**
* 不是加密文件夹
* @param list 文件夹中的内容
* @return 返回此文件夹是否加密.
*/
private boolean isNotEncryptedFolder(List<FileItemDTO> list) {
// 如果开启了 "搜索包含加密文件" 选项, 则直接返回 true.
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
if (BooleanUtil.isFalse(systemConfig.getSearchContainEncryptedFile())) {
return true;
}
// 遍历文件判断是否包含
for (FileItemDTO fileItemDTO : list) {
if (Objects.equals(ZFileConstant.PASSWORD_FILE_NAME, fileItemDTO.getName())) {
return false;
}
}
return true;
}
/**
* 获取所有缓存的 Key, 仅当开启缓存, 且缓存完成时, 可获取.
* @return 所有缓存的 Key
* @throws Exception 可能出现的异常
*/
public Set<String> getCacheKeys() throws Exception {
public Set<String> getCacheKeys() {
if (systemConfigService.getEnableCache() && fileAsyncCacheService.isCacheFinish()) {
Set<String> collect = selectAllFileList().stream().map(fileItemDTO -> {
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
@@ -216,4 +239,6 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
cache.config().setRefreshPolicy(refreshPolicy);
}
public abstract FileItemDTO getFileItem(String path);
}

View File

@@ -6,6 +6,7 @@ import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.util.StringUtils;
@@ -113,4 +114,14 @@ public abstract class AbstractS3FileService extends AbstractFileService {
String path = ObjectUtil.defaultIfNull(this.path, "");
return StringUtils.removeDuplicateSeparator(basePath + "/" + path);
}
@Override
public FileItemDTO getFileItem(String path) {
List<FileItemDTO> list = fileList(path);
if (list == null || list.size() == 0) {
throw new NotExistFileException();
}
return list.get(0);
}
}

View File

@@ -1,7 +1,7 @@
package im.zhaojun.common.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
@@ -92,7 +92,7 @@ public class SystemConfigService {
}
boolean oldEnableCache = getEnableCache();
boolean curEnableCache = ObjectUtil.defaultIfNull(systemConfigDTO.getEnableCache(), false);
boolean curEnableCache = BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
@@ -146,12 +146,12 @@ public class SystemConfigService {
public boolean getEnableCache() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return ObjectUtil.defaultIfNull(systemConfigDTO.getEnableCache(), false);
return BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
}
public boolean getSearchIgnoreCase() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return ObjectUtil.defaultIfNull(systemConfigDTO.getSearchIgnoreCase(), false);
return BooleanUtil.isTrue(systemConfigDTO.getSearchIgnoreCase());
}

View File

@@ -30,9 +30,7 @@ public class SystemService {
List<FileItemDTO> fileItemList = new ArrayList<>(fileService.fileList(path));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.FOOTER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setFooter(HttpUtil.getTextContent(fileItemDTO.getUrl()));
} else if (ZFileConstant.HEADER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
if (ZFileConstant.HEADER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setHeader(HttpUtil.getTextContent(fileItemDTO.getUrl()));
}
}

View File

@@ -90,4 +90,12 @@ public class FtpServiceImpl extends AbstractFileService implements FileService {
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.FTP;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setUrl(getDownloadUrl(path));
return fileItemDTO;
}
}

View File

@@ -1,6 +1,7 @@
package im.zhaojun.local.service;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
@@ -105,4 +106,26 @@ public class LocalServiceImpl extends AbstractFileService implements FileService
return StorageTypeEnum.LOCAL;
}
@Override
public FileItemDTO getFileItem(String path) {
String fullPath = StringUtils.concatPath(filePath, path);
File file = new File(fullPath);
if (!file.exists()) {
throw new NotExistFileException();
}
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setType(file.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE);
fileItemDTO.setTime(new Date(file.lastModified()));
fileItemDTO.setSize(file.length());
fileItemDTO.setName(file.getName());
fileItemDTO.setPath(filePath);
if (file.isFile()) {
fileItemDTO.setUrl(getDownloadUrl(path));
}
return fileItemDTO;
}
}

View File

@@ -0,0 +1,54 @@
package im.zhaojun.onedrive.china.service;
import im.zhaojun.onedrive.common.service.AbstractOneDriveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @author zhaojun
*/
@Service
public class OneDriveChinaService extends AbstractOneDriveService {
@Value("${zfile.onedirve-china.clientId}")
private String clientId;
@Value("${zfile.onedirve-china.redirectUri}")
private String redirectUri;
@Value("${zfile.onedirve-china.clientSecret}")
private String clientSecret;
@Value("${zfile.onedirve-china.scope}")
private String scope;
@Override
public String getGraphEndPoint() {
return "microsoftgraph.chinacloudapi.cn";
}
@Override
public String getAuthenticateEndPoint() {
return "login.partner.microsoftonline.cn";
}
@Override
public String getClientId() {
return clientId;
}
@Override
public String getRedirectUri() {
return redirectUri;
}
@Override
public String getClientSecret() {
return clientSecret;
}
@Override
public String getScope() {
return scope;
}
}

View File

@@ -0,0 +1,83 @@
package im.zhaojun.onedrive.china.service;
import im.zhaojun.common.config.GlobalScheduleTask;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author zhaojun
* @date 2020/1/12 13:53
*/
@Service
@Slf4j
public class OneDriveServiceChinaImpl extends AbstractFileService implements FileService {
@Resource
private GlobalScheduleTask globalScheduleTask;
@Resource
private StorageConfigService storageConfigService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessToken = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_TOKEN_KEY).getValue();
String refreshToken = stringStorageConfigMap.get(StorageConfigConstant.REFRESH_TOKEN_KEY).getValue();
if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
isInitialized = false;
} else {
globalScheduleTask.refreshOneDriveToken(getStorageTypeEnum());
isInitialized = testConnection();
}
} catch (Exception e) {
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
return oneDriveChinaService.list(path);
}
@Override
public String getDownloadUrl(String path) {
return null;
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.ONE_DRIVE_CHINA;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
try {
fileItemDTO = oneDriveChinaService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
}
}

View File

@@ -1,11 +1,14 @@
package im.zhaojun.onedrive.config;
package im.zhaojun.onedrive.common.config;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.international.service.OneDriveService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
@@ -22,13 +25,32 @@ public class OneDriveConfig {
@Resource
private StorageConfigService storageConfigService;
@Resource
@Lazy
private OneDriveService oneDriveService;
@Resource
@Lazy
private OneDriveChinaService oneDriveChinaService;
@Bean
public RestTemplate oneDriveRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
ClientHttpRequestInterceptor interceptor = (httpRequest, bytes, clientHttpRequestExecution) -> {
String host = httpRequest.getURI().getHost();
StorageTypeEnum type;
if (oneDriveChinaService.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE_CHINA;
} else if (oneDriveService.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE;
} else {
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
StorageConfig accessTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.ACCESS_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(type, StorageConfigConstant.ACCESS_TOKEN_KEY);
String tokenValue = String.format("%s %s", "Bearer", accessTokenConfig.getValue());
httpRequest.getHeaders().add("Authorization", tokenValue);
return clientHttpRequestExecution.execute(httpRequest, bytes);
@@ -37,5 +59,4 @@ public class OneDriveConfig {
return restTemplate;
}
}

View File

@@ -1,7 +1,8 @@
package im.zhaojun.onedrive.controller;
package im.zhaojun.onedrive.common.controller;
import im.zhaojun.onedrive.service.OneDriveService;
import im.zhaojun.onedrive.service.OneDriveToken;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import im.zhaojun.onedrive.international.service.OneDriveService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -19,6 +20,9 @@ public class OneDriveController {
@Resource
private OneDriveService oneDriveService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@GetMapping("/callback")
public String onedriveCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveService.getToken(code);
@@ -27,4 +31,13 @@ public class OneDriveController {
return "callback";
}
@GetMapping("/china-callback")
public String onedriveChinaCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveChinaService.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";
}
}

View File

@@ -1,4 +1,4 @@
package im.zhaojun.onedrive.service;
package im.zhaojun.onedrive.common.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package im.zhaojun.onedrive.service;
package im.zhaojun.onedrive.common.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
@@ -13,9 +13,8 @@ import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.repository.StorageConfigRepository;
import im.zhaojun.common.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@@ -23,31 +22,20 @@ import java.util.ArrayList;
import java.util.List;
/**
* @author zhaojun
* @date 2020/1/12 12:17
* @author Zhao Jun
* 2020/1/29 11:54
*/
@Service
public class OneDriveService {
public abstract class AbstractOneDriveService {
private static final String DRIVER_INFO_URL = "https://graph.microsoft.com/v1.0/drive";
protected static final String DRIVER_INFO_URL = "https://{graphEndPoint}/v1.0/me/drives";
private static final String DRIVER_ROOT_URL = "https://graph.microsoft.com/v1.0/drive/root/children";
protected static final String DRIVER_ROOT_URL = "https://{graphEndPoint}/v1.0/me/drive/root/children";
private static final String DRIVER_ITEMS_URL = "https://graph.microsoft.com/v1.0/drive/root:{path}:/children";
protected static final String DRIVER_ITEMS_URL = "https://{graphEndPoint}/v1.0/me/drive/root:{path}:/children";
private static final String AUTHENTICATE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
protected static final String DRIVER_ITEM_URL = "https://{graphEndPoint}/v1.0/me/drive/root:{path}";
@Value("${zfile.onedirve.clientId}")
private String clientId;
@Value("${zfile.onedirve.redirectUri}")
private String redirectUri;
@Value("${zfile.onedirve.clientSecret}")
private String clientSecret;
@Value("${zfile.onedirve.scope}")
private String scope;
protected static final String AUTHENTICATE_URL = "https://{authenticateEndPoint}/common/oauth2/v2.0/token";
@Resource
private RestTemplate oneDriveRestTemplate;
@@ -55,38 +43,42 @@ public class OneDriveService {
@Resource
private StorageConfigRepository storageConfigRepository;
public OneDriveToken getToken(String code) {
String param = "client_id=" + clientId +
"&redirect_uri=" + redirectUri +
"&client_secret=" + clientSecret +
"&code=" + code +
"&scope=" + scope +
"&grant_type=authorization_code";
HttpRequest post = HttpUtil.createPost(AUTHENTICATE_URL);
post.body(param, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public OneDriveToken getRefreshToken() {
StorageConfig refreshStorageConfig =
storageConfigRepository.findByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.REFRESH_TOKEN_KEY);
String param = "client_id=" + clientId +
"&redirect_uri=" + redirectUri +
"&client_secret=" + clientSecret +
String param = "client_id=" + getClientId() +
"&redirect_uri=" + getRedirectUri() +
"&client_secret=" + getClientSecret() +
"&refresh_token=" + refreshStorageConfig.getValue() +
"&grant_type=refresh_token";
HttpRequest post = HttpUtil.createPost(AUTHENTICATE_URL);
String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint());
HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl);
post.body(param, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public OneDriveToken getToken(String code) {
String param = "client_id=" + getClientId() +
"&redirect_uri=" + getRedirectUri() +
"&client_secret=" + getClientSecret() +
"&code=" + code +
"&scope=" + getScope() +
"&grant_type=authorization_code";
String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint());
HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl);
post.body(param, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public String getUserInfo() {
return oneDriveRestTemplate.getForObject(DRIVER_INFO_URL, String.class);
}
@@ -108,7 +100,7 @@ public class OneDriveService {
}
path = StringUtils.removeLastSeparator(path);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, path);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, getGraphEndPoint(), path);
String body = responseEntity.getBody();
JSONObject root = JSON.parseObject(body);
@@ -140,4 +132,41 @@ public class OneDriveService {
return result;
}
public FileItemDTO getItem(String path) {
String requestUrl;
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(DRIVER_ITEM_URL, String.class, path);
String body = responseEntity.getBody();
JSONObject fileItem = JSON.parseObject(body);
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(fileItem.getString("name"));
fileItemDTO.setSize(fileItem.getLong("size"));
fileItemDTO.setTime(fileItem.getDate("lastModifiedDateTime"));
if (fileItem.containsKey("file")) {
fileItemDTO.setUrl(fileItem.getString("@microsoft.graph.downloadUrl"));
fileItemDTO.setType(FileTypeEnum.FILE);
} else {
fileItemDTO.setType(FileTypeEnum.FOLDER);
}
fileItemDTO.setPath(path);
return fileItemDTO;
}
public abstract String getGraphEndPoint();
public abstract String getAuthenticateEndPoint();
public abstract String getClientId();
public abstract String getRedirectUri();
public abstract String getClientSecret();
public abstract String getScope();
}

View File

@@ -0,0 +1,54 @@
package im.zhaojun.onedrive.international.service;
import im.zhaojun.onedrive.common.service.AbstractOneDriveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @author zhaojun
*/
@Service
public class OneDriveService extends AbstractOneDriveService {
@Value("${zfile.onedirve.clientId}")
protected String clientId;
@Value("${zfile.onedirve.redirectUri}")
protected String redirectUri;
@Value("${zfile.onedirve.clientSecret}")
protected String clientSecret;
@Value("${zfile.onedirve.scope}")
protected String scope;
@Override
public String getGraphEndPoint() {
return "graph.microsoft.com";
}
@Override
public String getAuthenticateEndPoint() {
return "login.microsoftonline.com";
}
@Override
public String getClientId() {
return clientId;
}
@Override
public String getRedirectUri() {
return redirectUri;
}
@Override
public String getClientSecret() {
return clientSecret;
}
@Override
public String getScope() {
return scope;
}
}

View File

@@ -1,6 +1,7 @@
package im.zhaojun.onedrive.service;
package im.zhaojun.onedrive.international.service;
import im.zhaojun.common.config.GlobalScheduleTask;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
@@ -24,12 +25,6 @@ import java.util.Map;
@Slf4j
public class OneDriveServiceImpl extends AbstractFileService implements FileService {
public static final String SYSTEM_ONEDRIVE_CACHE_PREFIX = "zfile-onedrive-cache:";
public static final String SYSTEM_ONEDRIVE_CACHE_ASSESS_TOKEN_KEY = "accessToken";
public static final String SYSTEM_ONEDRIVE_CACHE_REFRESH_TOKEN_KEY = "refreshToken";
@Resource
private GlobalScheduleTask globalScheduleTask;
@@ -43,7 +38,7 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ONE_DRIVE);
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessToken = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_TOKEN_KEY).getValue();
String refreshToken = stringStorageConfigMap.get(StorageConfigConstant.REFRESH_TOKEN_KEY).getValue();
@@ -51,7 +46,7 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
isInitialized = false;
} else {
globalScheduleTask.refreshOneDriveToken();
globalScheduleTask.refreshOneDriveToken(getStorageTypeEnum());
isInitialized = testConnection();
}
} catch (Exception e) {
@@ -73,4 +68,16 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.ONE_DRIVE;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
try {
fileItemDTO = oneDriveService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
}
}

View File

@@ -3,6 +3,7 @@ package im.zhaojun.upyun.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import com.UpYun;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
@@ -108,4 +109,23 @@ public class UpYunServiceImpl extends AbstractFileService implements FileService
return StorageTypeEnum.UPYUN;
}
@Override
public FileItemDTO getFileItem(String path) {
List<FileItemDTO> list;
try {
int end = path.lastIndexOf("/");
list = fileList(path.substring(0, end));
} catch (Exception e) {
throw new NotExistFileException();
}
for (FileItemDTO fileItemDTO : list) {
String fullPath = StringUtils.concatUrl(fileItemDTO.getPath(), fileItemDTO.getName());
if (Objects.equals(fullPath, path)) {
return fileItemDTO;
}
}
throw new NotExistFileException();
}
}

View File

@@ -11,12 +11,6 @@
"defaultValue": "header.md",
"description": "头部文件 文件名."
},
{
"name": "zfile.constant.footer",
"type": "java.lang.String",
"defaultValue": "footer.md",
"description": "尾部文件 文件名."
},
{
"name": "zfile.constant.password",
"type": "java.lang.String",

View File

@@ -45,13 +45,17 @@ zfile:
timeout: 300
constant:
header: header.md
footer: footer.md
password: password.txt
onedirve:
clientId: 09939809-c617-43c8-a220-a93c1513c5d4
clientSecret: _l:zI-_yrW75lV8M61K@z.I2K@B/On6Q
redirectUri: https://zfile.jun6.net/onedirve/callback
scope: offline_access User.Read Files.ReadWrite.All
onedirve-china:
clientId: 4a72d927-1907-488d-9eb2-1b465c53c1c5
clientSecret: Y9CEA=82da5n-y_]KAWAgLH3?R9xf7Uw
redirectUri: https://zfile.jun6.net/onedirve/china-callback
scope: offline_access User.Read Files.ReadWrite.All
jetcache:
statIntervalMinutes: 0

View File

@@ -7,7 +7,9 @@ INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (6, 'username', '管理
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (7, 'password', '管理员密码');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (8, 'domain', '站点域名');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (9, 'enableCache', '是否开启缓存');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (10, 'searchContainEncryptedFile', '搜索包含加密文件');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (11, 'customCss', '自定义 CSS');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (12, 'customJs', '自定义 JS (可用于统计代码)');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (1, 'bucket-name', '云存储服务名称', 'upyun');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (2, 'username', '操作员名称', 'upyun');
@@ -51,4 +53,6 @@ INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (39, 'base-path',
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (40, 'base-path', '基路径', 'huawei');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (41, 'ftp', '基路径', 'ftp');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (42, 'accessToken', '访问令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (43, 'refreshToken', '刷新令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (43, 'refreshToken', '刷新令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (44, 'accessToken', '访问令牌', 'onedrive-china');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (45, 'refreshToken', '刷新令牌', 'onedrive-china');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title></title><link href=/css/adminIndex.25eab1c6.css rel=prefetch><link href=/css/install.b4e8b552.css rel=prefetch><link href=/js/adminIndex.456ac23a.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.f6845f54.js rel=prefetch><link href=/css/app.a731b1dd.css rel=preload as=style><link href=/css/chunk-vendors.39edcc5c.css rel=preload as=style><link href=/js/app.e0beab33.js rel=preload as=script><link href=/js/chunk-vendors.065da641.js rel=preload as=script><link href=/css/chunk-vendors.39edcc5c.css rel=stylesheet><link href=/css/app.a731b1dd.css rel=stylesheet></head><body><noscript><strong>We're sorry but zfile doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.065da641.js></script><script src=/js/app.e0beab33.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title></title><link href=/css/adminIndex.25eab1c6.css rel=prefetch><link href=/css/install.b4e8b552.css rel=prefetch><link href=/js/adminIndex.456ac23a.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.f6845f54.js rel=prefetch><link href=/css/app.22664175.css rel=preload as=style><link href=/css/chunk-vendors.39edcc5c.css rel=preload as=style><link href=/js/app.ce8716ec.js rel=preload as=script><link href=/js/chunk-vendors.065da641.js rel=preload as=script><link href=/css/chunk-vendors.39edcc5c.css rel=stylesheet><link href=/css/app.22664175.css rel=stylesheet></head><body><noscript><strong>We're sorry but zfile doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.065da641.js></script><script src=/js/app.ce8716ec.js></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long