Feat: get OneDrive thumbnails
This commit is contained in:
parent
6aee31341f
commit
06ff8b5a50
7 changed files with 94 additions and 12 deletions
|
@ -161,6 +161,17 @@ func (policy *Policy) IsDirectlyPreview() bool {
|
|||
return policy.Type == "local"
|
||||
}
|
||||
|
||||
// IsTransitUpload 返回此策略上传给定size文件时是否需要服务端中转
|
||||
func (policy *Policy) IsTransitUpload(size uint64) bool {
|
||||
if policy.Type == "local" {
|
||||
return true
|
||||
}
|
||||
if policy.Type == "onedrive" && size < 4*1024*1024 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPathGenerateNeeded 返回此策略是否需要在生成上传凭证时生成存储路径
|
||||
func (policy *Policy) IsPathGenerateNeeded() bool {
|
||||
return policy.Type != "remote"
|
||||
|
@ -171,6 +182,11 @@ func (policy *Policy) IsThumbGenerateNeeded() bool {
|
|||
return policy.Type == "local"
|
||||
}
|
||||
|
||||
// IsMockThumbNeeded 返回此策略是否需要在上传后默认当图像文件
|
||||
func (policy *Policy) IsMockThumbNeeded() bool {
|
||||
return policy.Type == "onedrive"
|
||||
}
|
||||
|
||||
// GetUploadURL 获取文件上传服务API地址
|
||||
func (policy *Policy) GetUploadURL() string {
|
||||
server, err := url.Parse(policy.Server)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/cache"
|
||||
"github.com/HFO4/cloudreve/pkg/request"
|
||||
|
@ -18,6 +19,13 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// SmallFileSize 单文件上传接口最大尺寸
|
||||
SmallFileSize uint64 = 4 * 1024 * 1024
|
||||
// ChunkSize 分片上传分片大小
|
||||
ChunkSize uint64 = 10 * 1024 * 1024
|
||||
)
|
||||
|
||||
// GetSourcePath 获取文件的绝对路径
|
||||
func (info *FileInfo) GetSourcePath() string {
|
||||
res, err := url.PathUnescape(
|
||||
|
@ -209,11 +217,41 @@ func (client *Client) makeBatchDeleteRequestsBody(files []string) string {
|
|||
return string(res)
|
||||
}
|
||||
|
||||
// GetThumbURL 获取给定尺寸的缩略图URL
|
||||
func (client *Client) GetThumbURL(ctx context.Context, dst string, w, h uint) (string, error) {
|
||||
dst = strings.TrimPrefix(dst, "/")
|
||||
cropOption := fmt.Sprintf("c%dx%d_Crop", w, h)
|
||||
requestURL := client.getRequestURL("me/drive/root:/"+dst+":/thumbnails") + "?select=" + cropOption
|
||||
|
||||
res, err := client.requestWithStr(ctx, "GET", requestURL, "", 200)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var (
|
||||
decodeErr error
|
||||
thumbRes ThumbResponse
|
||||
)
|
||||
decodeErr = json.Unmarshal([]byte(res), &thumbRes)
|
||||
if decodeErr != nil {
|
||||
return "", decodeErr
|
||||
}
|
||||
|
||||
if len(thumbRes.Value) == 1 {
|
||||
if res, ok := thumbRes.Value[0][cropOption]; ok {
|
||||
return res.(map[string]interface{})["url"].(string), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("无法生成缩略图")
|
||||
}
|
||||
|
||||
// MonitorUpload 监控客户端分片上传进度
|
||||
func (client *Client) MonitorUpload(uploadURL, callbackKey, path string, size uint64, ttl int64) {
|
||||
// 回调完成通知chan
|
||||
callbackChan := make(chan bool)
|
||||
callbackSignal.Store(callbackKey, callbackChan)
|
||||
defer callbackSignal.Delete(callbackKey)
|
||||
timeout := model.GetIntSetting("onedrive_monitor_timeout", 600)
|
||||
interval := model.GetIntSetting("onedrive_callback_check", 20)
|
||||
|
||||
|
@ -339,7 +377,7 @@ func (client *Client) request(ctx context.Context, method string, url string, bo
|
|||
if res.Response.StatusCode != expectedCode {
|
||||
decodeErr = json.Unmarshal([]byte(respBody), &errResp)
|
||||
if decodeErr != nil {
|
||||
return "", sysError(err)
|
||||
return "", sysError(decodeErr)
|
||||
}
|
||||
return "", &errResp
|
||||
}
|
||||
|
|
|
@ -24,7 +24,9 @@ func (handler Driver) Get(ctx context.Context, path string) (response.RSCloser,
|
|||
|
||||
// Put 将文件流保存到指定目录
|
||||
func (handler Driver) Put(ctx context.Context, file io.ReadCloser, dst string, size uint64) error {
|
||||
return errors.New("未实现")
|
||||
defer file.Close()
|
||||
_, err := handler.Client.PutFile(ctx, dst, file)
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete 删除一个或多个文件,
|
||||
|
@ -35,7 +37,25 @@ func (handler Driver) Delete(ctx context.Context, files []string) ([]string, err
|
|||
|
||||
// Thumb 获取文件缩略图
|
||||
func (handler Driver) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) {
|
||||
return nil, errors.New("未实现")
|
||||
var (
|
||||
thumbSize = [2]uint{400, 300}
|
||||
ok = false
|
||||
)
|
||||
if thumbSize, ok = ctx.Value(fsctx.ThumbSizeCtx).([2]uint); !ok {
|
||||
return nil, errors.New("无法获取缩略图尺寸设置")
|
||||
}
|
||||
|
||||
res, err := handler.Client.GetThumbURL(ctx, path, thumbSize[0], thumbSize[1])
|
||||
if err != nil {
|
||||
// 如果出现异常,就清空文件的pic_info
|
||||
if file, ok := ctx.Value(fsctx.FileModelCtx).(model.File); ok {
|
||||
file.UpdatePicInfo("")
|
||||
}
|
||||
}
|
||||
return &response.ContentResponse{
|
||||
Redirect: true,
|
||||
URL: res,
|
||||
}, err
|
||||
}
|
||||
|
||||
// Source 获取外链URL
|
||||
|
@ -63,8 +83,8 @@ func (handler Driver) Token(ctx context.Context, TTL int64, key string) (seriali
|
|||
return serializer.UploadCredential{}, errors.New("无法获取文件大小")
|
||||
}
|
||||
|
||||
// 如果小于10MB,则由服务端中转
|
||||
if fileSize <= 10*1024*1024 {
|
||||
// 如果小于4MB,则由服务端中转
|
||||
if fileSize <= SmallFileSize {
|
||||
return serializer.UploadCredential{}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -74,4 +74,9 @@ type BatchResponse struct {
|
|||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
// ThumbResponse 获取缩略图的响应
|
||||
type ThumbResponse struct {
|
||||
Value []map[string]interface{} `json:"value"`
|
||||
}
|
||||
|
||||
var callbackSignal sync.Map
|
||||
|
|
|
@ -271,6 +271,8 @@ func GenericAfterUpload(ctx context.Context, fs *FileSystem) error {
|
|||
// 异步尝试生成缩略图
|
||||
if fs.User.Policy.IsThumbGenerateNeeded() {
|
||||
go fs.GenerateThumbnail(ctx, file)
|
||||
} else if fs.User.Policy.IsMockThumbNeeded() {
|
||||
file.UpdatePicInfo("1,1")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -31,6 +31,7 @@ func (fs *FileSystem) GetThumb(ctx context.Context, id uint) (*response.ContentR
|
|||
|
||||
w, h := fs.GenerateThumbnailSize(0, 0)
|
||||
ctx = context.WithValue(ctx, fsctx.ThumbSizeCtx, [2]uint{w, h})
|
||||
ctx = context.WithValue(ctx, fsctx.FileModelCtx, fs.FileTarget[0])
|
||||
res, err := fs.Handler.Thumb(ctx, fs.FileTarget[0].SourceName)
|
||||
|
||||
// TODO 出错时重新生成缩略图
|
||||
|
|
|
@ -3,7 +3,7 @@ package controllers
|
|||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"github.com/HFO4/cloudreve/models"
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/filesystem"
|
||||
"github.com/HFO4/cloudreve/pkg/filesystem/driver/local"
|
||||
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
|
||||
|
@ -244,12 +244,6 @@ func FileUploadStream(c *gin.Context) {
|
|||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// 非本地策略时拒绝上传
|
||||
if user, ok := c.Get("user"); ok && user.(*model.User).Policy.Type != "local" {
|
||||
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 取得文件大小
|
||||
fileSize, err := strconv.ParseUint(c.Request.Header.Get("Content-Length"), 10, 64)
|
||||
if err != nil {
|
||||
|
@ -257,6 +251,12 @@ func FileUploadStream(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// 非可用策略时拒绝上传
|
||||
if user, ok := c.Get("user"); ok && !user.(*model.User).Policy.IsTransitUpload(fileSize) {
|
||||
c.JSON(200, serializer.Err(serializer.CodePolicyNotAllowed, "当前存储策略无法使用", nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 解码文件名和路径
|
||||
fileName, err := url.QueryUnescape(c.Request.Header.Get("X-FileName"))
|
||||
filePath, err := url.QueryUnescape(c.Request.Header.Get("X-Path"))
|
||||
|
|
Loading…
Add table
Reference in a new issue