Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/internal/model/obj.go
2321 views
1
package model
2
3
import (
4
"io"
5
"os"
6
"sort"
7
"strings"
8
"time"
9
10
"github.com/alist-org/alist/v3/pkg/http_range"
11
"github.com/alist-org/alist/v3/pkg/utils"
12
"github.com/dlclark/regexp2"
13
14
mapset "github.com/deckarep/golang-set/v2"
15
16
"github.com/maruel/natural"
17
)
18
19
type ObjUnwrap interface {
20
Unwrap() Obj
21
}
22
23
type StorageClassProvider interface {
24
StorageClass() string
25
}
26
27
type Obj interface {
28
GetSize() int64
29
GetName() string
30
ModTime() time.Time
31
CreateTime() time.Time
32
IsDir() bool
33
GetHash() utils.HashInfo
34
35
// The internal information of the driver.
36
// If you want to use it, please understand what it means
37
GetID() string
38
GetPath() string
39
}
40
41
// FileStreamer ->check FileStream for more comments
42
type FileStreamer interface {
43
io.Reader
44
io.Closer
45
Obj
46
GetMimetype() string
47
//SetReader(io.Reader)
48
NeedStore() bool
49
IsForceStreamUpload() bool
50
GetExist() Obj
51
SetExist(Obj)
52
//for a non-seekable Stream, RangeRead supports peeking some data, and CacheFullInTempFile still works
53
RangeRead(http_range.Range) (io.Reader, error)
54
//for a non-seekable Stream, if Read is called, this function won't work
55
CacheFullInTempFile() (File, error)
56
SetTmpFile(r *os.File)
57
GetFile() File
58
}
59
60
type UpdateProgress func(percentage float64)
61
62
// Reference implementation from OpenListTeam:
63
// https://github.com/OpenListTeam/OpenList/blob/a703b736c9346c483bae56905a39bc07bf781cff/internal/model/obj.go#L58
64
func UpdateProgressWithRange(inner UpdateProgress, start, end float64) UpdateProgress {
65
return func(p float64) {
66
if p < 0 {
67
p = 0
68
}
69
if p > 100 {
70
p = 100
71
}
72
scaled := start + (end-start)*(p/100.0)
73
inner(scaled)
74
}
75
}
76
77
type URL interface {
78
URL() string
79
}
80
81
type Thumb interface {
82
Thumb() string
83
}
84
85
type SetPath interface {
86
SetPath(path string)
87
}
88
89
func SortFiles(objs []Obj, orderBy, orderDirection string) {
90
if orderBy == "" {
91
return
92
}
93
sort.Slice(objs, func(i, j int) bool {
94
switch orderBy {
95
case "name":
96
{
97
c := natural.Less(objs[i].GetName(), objs[j].GetName())
98
if orderDirection == "desc" {
99
return !c
100
}
101
return c
102
}
103
case "size":
104
{
105
if orderDirection == "desc" {
106
return objs[i].GetSize() >= objs[j].GetSize()
107
}
108
return objs[i].GetSize() <= objs[j].GetSize()
109
}
110
case "modified":
111
if orderDirection == "desc" {
112
return objs[i].ModTime().After(objs[j].ModTime())
113
}
114
return objs[i].ModTime().Before(objs[j].ModTime())
115
}
116
return false
117
})
118
}
119
120
func ExtractFolder(objs []Obj, extractFolder string) {
121
if extractFolder == "" {
122
return
123
}
124
front := extractFolder == "front"
125
sort.SliceStable(objs, func(i, j int) bool {
126
if objs[i].IsDir() || objs[j].IsDir() {
127
if !objs[i].IsDir() {
128
return !front
129
}
130
if !objs[j].IsDir() {
131
return front
132
}
133
}
134
return false
135
})
136
}
137
138
func WrapObjName(objs Obj) Obj {
139
return &ObjWrapName{Name: utils.MappingName(objs.GetName()), Obj: objs}
140
}
141
142
func WrapObjsName(objs []Obj) {
143
for i := 0; i < len(objs); i++ {
144
objs[i] = &ObjWrapName{Name: utils.MappingName(objs[i].GetName()), Obj: objs[i]}
145
}
146
}
147
148
func WrapObjStorageClass(obj Obj, storageClass string) Obj {
149
if storageClass == "" {
150
return obj
151
}
152
return &ObjWrapStorageClass{Obj: obj, storageClass: storageClass}
153
}
154
155
func UnwrapObj(obj Obj) Obj {
156
if unwrap, ok := obj.(ObjUnwrap); ok {
157
obj = unwrap.Unwrap()
158
}
159
return obj
160
}
161
162
func GetThumb(obj Obj) (thumb string, ok bool) {
163
if obj, ok := obj.(Thumb); ok {
164
return obj.Thumb(), true
165
}
166
if unwrap, ok := obj.(ObjUnwrap); ok {
167
return GetThumb(unwrap.Unwrap())
168
}
169
return thumb, false
170
}
171
172
func GetUrl(obj Obj) (url string, ok bool) {
173
if obj, ok := obj.(URL); ok {
174
return obj.URL(), true
175
}
176
if unwrap, ok := obj.(ObjUnwrap); ok {
177
return GetUrl(unwrap.Unwrap())
178
}
179
return url, false
180
}
181
182
func GetStorageClass(obj Obj) (string, bool) {
183
if provider, ok := obj.(StorageClassProvider); ok {
184
value := provider.StorageClass()
185
if value == "" {
186
return "", false
187
}
188
return value, true
189
}
190
if unwrap, ok := obj.(ObjUnwrap); ok {
191
return GetStorageClass(unwrap.Unwrap())
192
}
193
return "", false
194
}
195
196
func GetRawObject(obj Obj) *Object {
197
switch v := obj.(type) {
198
case *ObjThumbURL:
199
return &v.Object
200
case *ObjThumb:
201
return &v.Object
202
case *ObjectURL:
203
return &v.Object
204
case *Object:
205
return v
206
}
207
return nil
208
}
209
210
// Merge
211
func NewObjMerge() *ObjMerge {
212
return &ObjMerge{
213
set: mapset.NewSet[string](),
214
}
215
}
216
217
type ObjMerge struct {
218
regs []*regexp2.Regexp
219
set mapset.Set[string]
220
}
221
222
func (om *ObjMerge) Merge(objs []Obj, objs_ ...Obj) []Obj {
223
newObjs := make([]Obj, 0, len(objs)+len(objs_))
224
newObjs = om.insertObjs(om.insertObjs(newObjs, objs...), objs_...)
225
return newObjs
226
}
227
228
func (om *ObjMerge) insertObjs(objs []Obj, objs_ ...Obj) []Obj {
229
for _, obj := range objs_ {
230
if om.clickObj(obj) {
231
objs = append(objs, obj)
232
}
233
}
234
return objs
235
}
236
237
func (om *ObjMerge) clickObj(obj Obj) bool {
238
for _, reg := range om.regs {
239
if isMatch, _ := reg.MatchString(obj.GetName()); isMatch {
240
return false
241
}
242
}
243
return om.set.Add(obj.GetName())
244
}
245
246
func (om *ObjMerge) InitHideReg(hides string) {
247
rs := strings.Split(hides, "\n")
248
om.regs = make([]*regexp2.Regexp, 0, len(rs))
249
for _, r := range rs {
250
om.regs = append(om.regs, regexp2.MustCompile(r, regexp2.None))
251
}
252
}
253
254
func (om *ObjMerge) Reset() {
255
om.set.Clear()
256
}
257
258