132 lines
3.6 KiB
Go
132 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func (a *App) upload(t *Task) {
|
|
if t.RemotePath != "" && t.Status == "done" {
|
|
return
|
|
}
|
|
storage, root, enabled := a.storageForTask(t)
|
|
if !enabled || storage == nil || root == "" {
|
|
if t.Status == "upload_pending" {
|
|
if err := a.db.Model(t).Updates(map[string]any{
|
|
"status": "done", "error": "",
|
|
}).Error; err != nil {
|
|
return
|
|
}
|
|
t.Status, t.Error = "done", ""
|
|
}
|
|
return
|
|
}
|
|
if !a.claimUpload(t) {
|
|
return
|
|
}
|
|
remote := strings.TrimRight(root, "/") + "/" + safe(t.Artist) + "/" +
|
|
safe(t.Album) + "/" + safe(t.Title) + "." + safe(t.Format)
|
|
if err := storage.MkdirAll(filepath.ToSlash(filepath.Dir(remote))); err != nil {
|
|
a.failUpload(t, err)
|
|
return
|
|
}
|
|
fi, statErr := os.Stat(t.LocalPath)
|
|
if statErr != nil {
|
|
if a.recoverMissingLocalUpload(t) {
|
|
return
|
|
}
|
|
a.failUpload(t, statErr)
|
|
return
|
|
}
|
|
if same, _ := storage.ExistsSameSize(remote, fi.Size()); same {
|
|
t.RemotePath = remote
|
|
t.Status, t.Progress, t.Error = "done", 100, ""
|
|
_ = a.db.Model(t).Updates(map[string]any{
|
|
"remote_path": remote, "status": "done",
|
|
"progress": 100, "error": "",
|
|
}).Error
|
|
a.cleanupLocalFile(t)
|
|
return
|
|
}
|
|
if err := storage.Upload(t.LocalPath, remote); err != nil {
|
|
a.failUpload(t, err)
|
|
return
|
|
}
|
|
t.RemotePath = remote
|
|
t.Status, t.Progress, t.Error = "done", 100, ""
|
|
if err := a.db.Model(t).Updates(map[string]any{
|
|
"remote_path": remote, "status": "done",
|
|
"progress": 100, "error": "",
|
|
}).Error; err != nil {
|
|
return
|
|
}
|
|
if a.cfg.WebDAVVersionPolicy == "replace_lower" {
|
|
a.cleanupLowerQualityVersions(t, storage)
|
|
}
|
|
a.cleanupLocalFile(t)
|
|
}
|
|
|
|
func (a *App) cleanupLocalFile(t *Task) {
|
|
if a.cfg.LocalFilePolicy != "delete_after_upload" || t.LocalPath == "" {
|
|
return
|
|
}
|
|
if t.AssetID != 0 {
|
|
var pending int64
|
|
if err := a.db.Model(&Task{}).
|
|
Where("asset_id = ? AND id <> ? AND local_path = ? AND "+
|
|
"(status IN ? OR (status = ? AND (remote_path = '' OR remote_path IS NULL)))",
|
|
t.AssetID, t.ID, t.LocalPath,
|
|
[]string{"pending", "resolving", "downloading", "uploading", "upload_pending"},
|
|
"done").Count(&pending).Error; err != nil {
|
|
return
|
|
}
|
|
if pending > 0 {
|
|
return
|
|
}
|
|
}
|
|
|
|
if err := os.Remove(t.LocalPath); err != nil && !os.IsNotExist(err) {
|
|
t.Error = "WebDAV 上传成功,但删除本地文件失败: " + err.Error()
|
|
_ = a.db.Save(t)
|
|
return
|
|
}
|
|
if t.AssetID != 0 {
|
|
_ = a.db.Model(&MediaAsset{}).
|
|
Where("id = ? AND local_path = ?", t.AssetID, t.LocalPath).
|
|
Updates(map[string]any{
|
|
"status": "evicted", "local_path": "",
|
|
"size": 0, "owner_task_id": 0, "lease_until": nil,
|
|
}).Error
|
|
}
|
|
}
|
|
|
|
func (a *App) cleanupLowerQualityVersions(t *Task, storage RemoteStorage) {
|
|
levels := map[string]int{"standard": 1, "exhigh": 2, "sq": 3,
|
|
"lossless": 4, "hires": 5, "jyeffect": 6, "sky": 7,
|
|
"jymaster": 8, "atmos": 9, "atmos_plus": 10, "master": 11}
|
|
current := qualityRank(levels, t.ActualQuality, t.ResolvedQuality, t.Quality)
|
|
if current == 0 {
|
|
return
|
|
}
|
|
var old []Task
|
|
a.db.Where("user_id = ? AND artist = ? AND title = ? AND album = ? "+
|
|
"AND status = ? AND id <> ?", t.UserID, t.Artist, t.Title, t.Album, "done", t.ID).Find(&old)
|
|
for _, candidate := range old {
|
|
q := qualityRank(levels, candidate.ActualQuality, candidate.ResolvedQuality, candidate.Quality)
|
|
if q == 0 || q >= current || candidate.RemotePath == "" || candidate.RemotePath == t.RemotePath {
|
|
continue
|
|
}
|
|
_ = storage.Remove(candidate.RemotePath)
|
|
}
|
|
}
|
|
|
|
func qualityRank(levels map[string]int, values ...string) int {
|
|
for _, q := range values {
|
|
if n := levels[q]; n > 0 {
|
|
return n
|
|
}
|
|
}
|
|
return 0
|
|
}
|