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