Skip to content

Commit 81a54f9

Browse files
committed
feat: implement ApplyApiPathRule and update path handling in artwork and picture routes
1 parent c8d46ab commit 81a54f9

File tree

12 files changed

+88
-16
lines changed

12 files changed

+88
-16
lines changed

adapter/adapter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func ConvertToFeedItems(ctx context.Context, artworks []*types.Artwork) []*feeds
177177
</article>
178178
`,
179179
html.EscapeString(artwork.Title),
180-
html.EscapeString(common.ApplyPathRule(artwork.Pictures[0].StorageInfo.Regular.Path)),
180+
html.EscapeString(common.ApplyApiPathRule(artwork.Pictures[0].StorageInfo.Regular.Path)),
181181
html.EscapeString(artwork.Title),
182182
html.EscapeString(artwork.Description),
183183
html.EscapeString(artwork.Artist.Name),

api/restful/routers/artwork/list.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func RandomArtworkPreview(ctx *gin.Context) {
8383
case types.StorageTypeLocal:
8484
ctx.File(picture.StorageInfo.Regular.Path)
8585
case types.StorageTypeAlist:
86-
ctx.Redirect(http.StatusFound, common.ApplyPathRule(picture.StorageInfo.Regular.Path))
86+
ctx.Redirect(http.StatusFound, common.ApplyApiPathRule(picture.StorageInfo.Regular.Path))
8787
default:
8888
data, err := storage.GetFile(ctx, picture.StorageInfo.Regular)
8989
if err != nil {

api/restful/routers/artwork/response_types.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ func ResponseDataFromArtwork(artwork *types.Artwork) *ArtworkResponseData {
5656
for i, picture := range artwork.Pictures {
5757
var thumbnail, regular string
5858
if picture.StorageInfo.Thumb.Type == types.StorageTypeAlist {
59-
thumbnail = common.ApplyPathRule(picture.StorageInfo.Thumb.Path)
59+
thumbnail = common.ApplyApiPathRule(picture.StorageInfo.Thumb.Path)
6060
} else {
6161
thumbnail = picture.Thumbnail
6262
}
6363
if picture.StorageInfo.Regular.Type == types.StorageTypeAlist {
64-
regular = common.ApplyPathRule(picture.StorageInfo.Regular.Path)
64+
regular = common.ApplyApiPathRule(picture.StorageInfo.Regular.Path)
6565
} else {
6666
regular = picture.Thumbnail
6767
}

api/restful/routers/picture/handlers.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func RandomPicture(ctx *gin.Context) {
100100
case types.StorageTypeLocal:
101101
ctx.File(picture.StorageInfo.Regular.Path)
102102
case types.StorageTypeAlist:
103-
ctx.Redirect(http.StatusFound, common.ApplyPathRule(picture.StorageInfo.Regular.Path))
103+
ctx.Redirect(http.StatusFound, common.ApplyApiPathRule(picture.StorageInfo.Regular.Path))
104104
default:
105105
data, err := storage.GetFile(ctx, picture.StorageInfo.Regular)
106106
if err != nil {

common/strings.go

+5-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"encoding/hex"
66
"html"
77
"math/rand"
8-
"net/url"
8+
"path"
99
"regexp"
1010
"strings"
1111

@@ -125,16 +125,12 @@ func ExtractTagsFromText(text string) []string {
125125
return tags
126126
}
127127

128-
func ApplyPathRule(path string) string {
128+
func ApplyApiPathRule(originPath string) string {
129129
for _, rule := range config.Cfg.API.PathRules {
130-
if strings.HasPrefix(path, rule.Path) {
131-
parsedUrl, err := url.JoinPath(rule.JoinPrefix, strings.TrimPrefix(path, rule.TrimPrefix))
132-
if err != nil {
133-
Logger.Errorf("Failed to parse url: %s", err)
134-
return rule.JoinPrefix + strings.TrimPrefix(path, rule.TrimPrefix)
135-
}
130+
if strings.HasPrefix(originPath, rule.Path) {
131+
parsedUrl := path.Join(rule.JoinPrefix, strings.TrimPrefix(originPath, rule.TrimPrefix))
136132
return parsedUrl
137133
}
138134
}
139-
return path
135+
return originPath
140136
}

config/api.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ type apiConfig struct {
1818
TokenExpire int `toml:"token_expire" mapstructure:"token_expire" json:"token_expire" yaml:"token_expire"`
1919
RefreshTokenExpire int `toml:"refresh_token_expire" mapstructure:"refresh_token_expire" json:"refresh_token_expire" yaml:"refresh_token_expire"`
2020

21-
PathRules []PathRule `toml:"path_rules" mapstructure:"path_rules" json:"path_rules" yaml:"path_rules"`
21+
PathRules []ApiPathRule `toml:"path_rules" mapstructure:"path_rules" json:"path_rules" yaml:"path_rules"`
2222

2323
Cache apiCacheConfig `toml:"cache" mapstructure:"cache" json:"cache" yaml:"cache"`
2424
}
2525

26-
type PathRule struct {
26+
type ApiPathRule struct {
2727
Path string `toml:"path" mapstructure:"path" json:"path" yaml:"path"`
2828
TrimPrefix string `toml:"trim_prefix" mapstructure:"trim_prefix" json:"trim_prefix" yaml:"trim_prefix"`
2929
JoinPrefix string `toml:"join_prefix" mapstructure:"join_prefix" json:"join_prefix" yaml:"join_prefix"`

config/storage.go

+21
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,32 @@ type storageConfigs struct {
88
ThumbFormat string `toml:"thumb_format" mapstructure:"thumb_format" json:"thumb_format" yaml:"thumb_format"`
99
CacheDir string `toml:"cache_dir" mapstructure:"cache_dir" json:"cache_dir" yaml:"cache_dir"`
1010
CacheTTL uint `toml:"cache_ttl" mapstructure:"cache_ttl" json:"cache_ttl" yaml:"cache_ttl"`
11+
Rules []storageRuleConfig `toml:"rules" mapstructure:"rules" json:"rules" yaml:"rules"`
1112
Webdav StorageWebdavConfig `toml:"webdav" mapstructure:"webdav" json:"webdav" yaml:"webdav"`
1213
Local StorageLocalConfig `toml:"local" mapstructure:"local" json:"local" yaml:"local"`
1314
Alist StorageAlistConfig `toml:"alist" mapstructure:"alist" json:"alist" yaml:"alist"`
1415
}
1516

17+
type storageRuleConfig struct {
18+
/*
19+
Match: 进行 与 匹配
20+
Replace: 依次进行替换
21+
example:
22+
match: {storage_type: "webdav", path_prefix: "/onedrive"}
23+
replace: {rewrite_storage: "local", trim_prefix: "/onedrive", join_prefix: "/local/manyacg"}
24+
此规则被应用后, storage 在获取 webdav 存储驱动下的以 /onedrive 开头的图片时, 会去寻找 local 存储驱动下的以 /local/manyacg 开头的图片(路径前缀被替换)
25+
*/
26+
27+
// Match
28+
StorageType string `toml:"storage_type" mapstructure:"storage_type" json:"storage_type" yaml:"storage_type"`
29+
PathPrefix string `toml:"path_prefix" mapstructure:"path_prefix" json:"path_prefix" yaml:"path_prefix"`
30+
31+
// Replace
32+
RewriteStorage string `toml:"rewrite_storage" mapstructure:"rewrite_storage" json:"rewrite_storage" yaml:"rewrite_storage"`
33+
TrimPrefix string `toml:"trim_prefix" mapstructure:"trim_prefix" json:"trim_prefix" yaml:"trim_prefix"`
34+
JoinPrefix string `toml:"join_prefix" mapstructure:"join_prefix" json:"join_prefix" yaml:"join_prefix"`
35+
}
36+
1637
type StorageWebdavConfig struct {
1738
Enable bool `toml:"enable" mapstructure:"enable" json:"enable" yaml:"enable"`
1839
URL string `toml:"url" mapstructure:"url" json:"url" yaml:"url"`

storage/local/local.go

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func (l *Local) Save(ctx context.Context, filePath string, storagePath string) (
5050
}
5151

5252
func (l *Local) GetFile(ctx context.Context, detail *types.StorageDetail) ([]byte, error) {
53+
common.Logger.Debugf("getting file %s", detail.Path)
5354
return os.ReadFile(detail.Path)
5455
}
5556

@@ -58,5 +59,6 @@ func (l *Local) GetFileStream(ctx context.Context, detail *types.StorageDetail)
5859
}
5960

6061
func (l *Local) Delete(ctx context.Context, detail *types.StorageDetail) error {
62+
common.Logger.Debugf("deleting file %s", detail.Path)
6163
return common.PurgeFile(detail.Path)
6264
}

storage/storage.go

+4
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ func Save(ctx context.Context, filePath string, storagePath string, storageType
148148
var storageLocks sync.Map
149149

150150
func GetFile(ctx context.Context, detail *types.StorageDetail) ([]byte, error) {
151+
detail, err := applyRule(detail)
152+
if err != nil {
153+
return nil, err
154+
}
151155
if detail.Type != types.StorageTypeLocal {
152156
lock, _ := storageLocks.LoadOrStore(detail.String(), &sync.Mutex{})
153157
lock.(*sync.Mutex).Lock()

storage/utils.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package storage
2+
3+
import (
4+
"errors"
5+
"path"
6+
"strings"
7+
8+
"github.com/krau/ManyACG/config"
9+
"github.com/krau/ManyACG/types"
10+
)
11+
12+
var (
13+
ErrNilStorageDetail = errors.New("storage detail is nil")
14+
ErrStorageNotFound = errors.New("storage not found")
15+
)
16+
17+
func applyRule(detail *types.StorageDetail) (*types.StorageDetail, error) {
18+
if detail == nil {
19+
return nil, ErrNilStorageDetail
20+
}
21+
22+
currentType := detail.Type.String()
23+
currentPath := detail.Path
24+
25+
if currentType == "" || currentPath == "" {
26+
return detail, nil
27+
}
28+
29+
for _, rule := range config.Cfg.Storage.Rules {
30+
if !(currentType == rule.StorageType && strings.HasPrefix(currentPath, rule.PathPrefix)) {
31+
continue
32+
}
33+
if rule.RewriteStorage == "" {
34+
continue
35+
}
36+
_, ok := Storages[types.StorageType(rule.RewriteStorage)]
37+
if !ok {
38+
return nil, ErrStorageNotFound
39+
}
40+
detail.Type = types.StorageType(rule.RewriteStorage)
41+
detail.Path = path.Join(rule.JoinPrefix, strings.TrimPrefix(currentPath, rule.TrimPrefix))
42+
}
43+
return detail, nil
44+
}

telegram/handlers/admin_edit_artwork.go

+1
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ func AutoTaggingArtwork(ctx context.Context, bot *telego.Bot, message telego.Mes
397397
}
398398
}())
399399
if err != nil {
400+
common.Logger.Errorf("Get picture file from storage failed: %s", err)
400401
file, err = common.DownloadWithCache(ctx, picture.Original, nil)
401402
}
402403
if err != nil {

types/storage.go

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package types
22

33
type StorageType string
44

5+
func (s StorageType) String() string {
6+
return string(s)
7+
}
8+
59
const (
610
StorageTypeWebdav StorageType = "webdav"
711
StorageTypeLocal StorageType = "local"

0 commit comments

Comments
 (0)