├── .gitignore ├── src ├── utils │ ├── init.go │ ├── storage │ │ ├── init.go │ │ └── minio.go │ ├── config.go │ └── file.go ├── image-pro │ ├── new.go │ ├── init.go │ ├── encode.go │ └── transform.go └── middlewares │ ├── handle-cache.go │ └── handle-src.go ├── config.example.yml ├── image-pro.conf ├── readme.md ├── cmd ├── server │ └── main.go └── m3u8-server │ └── main.go ├── nginx.conf ├── Makefile ├── go.mod └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | config.yml 2 | bin 3 | .idea 4 | .DS_Store 5 | data -------------------------------------------------------------------------------- /src/utils/init.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func init() { 4 | initConfig() 5 | } 6 | -------------------------------------------------------------------------------- /config.example.yml: -------------------------------------------------------------------------------- 1 | minio: 2 | endpoint: "" 3 | accessKeyId: "" 4 | secretAccessKey: "" 5 | server: 6 | hostName: "" 7 | debug: true 8 | remoteEnable: false 9 | dataPath: "" 10 | fileAddress: "0.0.0.0:8009" 11 | m3u8Address: "0.0.0.0:8008" 12 | nodes: 13 | - "https://a01.xx.com/" 14 | - "https://a01.xx.com/" 15 | - "https://a01.xx.com" -------------------------------------------------------------------------------- /image-pro.conf: -------------------------------------------------------------------------------- 1 | [program:image-pro] 2 | process_name=%(program_name)s_%(process_num)02d 3 | directory=/data/image-pro 4 | command=/data/image-pro/server web 5 | autostart=true 6 | autorestart=true 7 | stopasgroup=true 8 | killasgroup=true 9 | user=root 10 | numprocs=1 11 | redirect_stderr=true 12 | stdout_logfile=/data/image-pro/run.log 13 | stopwaitsecs=3600 14 | -------------------------------------------------------------------------------- /src/image-pro/new.go: -------------------------------------------------------------------------------- 1 | package imagepro 2 | 3 | import ( 4 | "github.com/fishtailstudio/imgo" 5 | ) 6 | 7 | func New(src string, opts *Options) *ImagePro { 8 | i := &ImagePro{} 9 | i.Lossless = false 10 | i.Exact = false 11 | img := imgo.Load(src) 12 | i.image = img.ToImage() 13 | if opts.Quality == nil { 14 | opts.Quality = 85 15 | } 16 | i.extension = img.Extension() 17 | i.opts = opts 18 | return i 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/storage/init.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "path" 5 | "s3cache/src/utils" 6 | ) 7 | 8 | func initPath() { 9 | dataPath := utils.GetConfig().Server.DataPath 10 | if dataPath == "" { 11 | dataPath = utils.AppPath("data") 12 | } 13 | srcPath := path.Join(dataPath, "src") 14 | cachePath := path.Join(dataPath, "cache") 15 | utils.MakeDir(srcPath) 16 | utils.MakeDir(cachePath) 17 | } 18 | func init() { 19 | initPath() 20 | initMinioClient() 21 | } 22 | -------------------------------------------------------------------------------- /src/image-pro/init.go: -------------------------------------------------------------------------------- 1 | package imagepro 2 | 3 | import ( 4 | "image" 5 | ) 6 | 7 | type Options struct { 8 | Format string 9 | Flip interface{} 10 | Rotate interface{} 11 | X int 12 | Y int 13 | Mode string 14 | Width int 15 | Pixelate interface{} 16 | Height int 17 | Quality interface{} 18 | } 19 | type ImagePro struct { 20 | image image.Image 21 | Lossless bool 22 | Exact bool 23 | extension string 24 | opts *Options 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/storage/minio.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "context" 5 | "github.com/minio/minio-go/v7" 6 | "github.com/minio/minio-go/v7/pkg/credentials" 7 | "log" 8 | "s3cache/src/utils" 9 | ) 10 | 11 | var minioClient *minio.Client = nil 12 | 13 | func initMinioClient() { 14 | cfg := utils.GetConfig() 15 | client, err := minio.New(cfg.Minio.Endpoint, &minio.Options{ 16 | Creds: credentials.NewStaticV4(cfg.Minio.AccessKeyId, cfg.Minio.SecretAccessKey, ""), 17 | Secure: true, 18 | }) 19 | if err != nil { 20 | log.Fatalln(err) 21 | } 22 | minioClient = client 23 | } 24 | func DownloadObject(bucket string, objectName string, filePath string) error { 25 | err := minioClient.FGetObject(context.Background(), bucket, objectName, filePath, minio.GetObjectOptions{}) 26 | return err 27 | } 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 一个可用s3作为后端的缓存服务器 也可作为图片服务器 2 | # 支持webp jpp png bmp等图片实时转码 3 | ## 配置文件 4 | ```yaml 5 | minio: 6 | endpoint: "" 7 | accessKeyId: "" 8 | secretAccessKey: "" 9 | server: 10 | debug: false 11 | # 可以默认关闭 12 | remoteEnable: false 13 | dataPath: "绝对路径 不设置则默认为当前目录的 data目录" 14 | address: "0.0.0.0:8009" 15 | ``` 16 | 17 | # 请求示例 18 | 19 | ### 请求参数 20 | 21 | ```json 22 | { 23 | "bucket": "cover",//必填 24 | "f": "webp", // 支持 jpg png bmp webp 25 | "w": 100, 26 | "h": 1500, 27 | "m": "resize" // 支持 thumbnail resize 28 | } 29 | ``` 30 | 31 | ```shell 32 | /file/{文件路径} 33 | ``` 34 | 35 | ```shell 36 | https://xxx.com/file/31/3d/313d8ce3f1174bcb53374d7d4d.jpg?bucket=cover 37 | # 源文件对应的目录为 38 | {dataPath}/cover/31/3d/313d8ce3f11742ce927bcb53374d7d4d.jpg 39 | ``` 40 | 41 | ### 参开supervisor配置 42 | >image-pro.conf 43 | ### 参考nginx配置 44 | >nginx.conf 45 | 46 | 47 | 48 | ### 必看 49 | 50 | ```shell 51 | # ubuntu 安装 52 | apt-get install musl-dev 53 | ``` -------------------------------------------------------------------------------- /cmd/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "log" 6 | "s3cache/src/middlewares" 7 | "s3cache/src/utils" 8 | ) 9 | 10 | func RunServer() { 11 | log.Println("run server " + utils.GetConfig().Server.FileAddress) 12 | if utils.GetConfig().Server.Debug { 13 | gin.SetMode(gin.DebugMode) 14 | } else { 15 | gin.SetMode(gin.ReleaseMode) 16 | } 17 | var r = gin.Default() 18 | // 第一层用户接收用户请求 19 | fileRoute := r.Group("/file") 20 | fileRoute.Use(middlewares.HandleSrc(r)) 21 | fileRoute.Static("/", utils.DataPath("src")) 22 | // 用于跳转源文件 23 | srcRoute := r.Group("/src") 24 | srcRoute.Static("/", utils.DataPath("src")) 25 | // 用于跳转已处理的文件 26 | cacheRoute := r.Group("/cache") 27 | cacheRoute.Use(middlewares.HandleCache()) 28 | cacheRoute.Static("/", utils.DataPath("cache")) 29 | err := r.Run(utils.GetConfig().Server.FileAddress) 30 | if err != nil { 31 | return 32 | } 33 | } 34 | func main() { 35 | RunServer() 36 | } 37 | -------------------------------------------------------------------------------- /src/utils/config.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "gopkg.in/yaml.v3" 5 | "log" 6 | ) 7 | 8 | type AppConfig struct { 9 | Minio struct { 10 | Endpoint string `yaml:"endpoint"` 11 | AccessKeyId string `yaml:"accessKeyId"` 12 | SecretAccessKey string `yaml:"secretAccessKey"` 13 | } 14 | Server struct { 15 | HostName string `yaml:"hostName"` 16 | RemoteEnable bool `yaml:"remoteEnable"` 17 | FileAddress string `yaml:"fileAddress"` 18 | M3u8Address string `yaml:"m3u8Address"` 19 | DataPath string `yaml:"dataPath"` 20 | Debug bool `yaml:"debug"` 21 | Nodes []string `yaml:"nodes"` 22 | } 23 | } 24 | 25 | var c = AppConfig{} 26 | 27 | func initConfig() { 28 | log.Println("init config") 29 | content := ReadFile(AppPath("config.yml")) 30 | err := yaml.Unmarshal(content, &c) 31 | if err != nil { 32 | log.Fatalf("error: %v", err) 33 | } 34 | } 35 | func GetConfig() AppConfig { 36 | return c 37 | } 38 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | server{ 2 | listen 80; 3 | server_name a01.xx.com; 4 | return 301 https://$server_name$request_uri; 5 | } 6 | server{ 7 | listen 443 ssl http2; 8 | server_name a01.xx.com; 9 | ssl_certificate /root/.lego/certificates/a01.x.com.crt; 10 | ssl_certificate_key /root/.lego/certificates/a01.xx.com.key; 11 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 12 | ssl_ciphers HIGH:!aNULL:!MD5; 13 | gzip on; 14 | gzip_min_length 1k; 15 | gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml; 16 | gzip_vary on; 17 | gzip_buffers 32 4k; 18 | gzip_comp_level 1; 19 | charset utf-8; 20 | location / { 21 | proxy_pass http://localhost:8009; 22 | proxy_set_header X-Forwarded-For $remote_addr; 23 | proxy_set_header X-Forwarded-Proto $scheme; 24 | proxy_set_header Host $host; 25 | client_max_body_size 50M; 26 | proxy_http_version 1.1; 27 | } 28 | } -------------------------------------------------------------------------------- /src/image-pro/encode.go: -------------------------------------------------------------------------------- 1 | package imagepro 2 | 3 | import ( 4 | "bytes" 5 | "github.com/chai2010/webp" 6 | "golang.org/x/image/bmp" 7 | "golang.org/x/image/tiff" 8 | "image/jpeg" 9 | "image/png" 10 | "log" 11 | ) 12 | 13 | func (i *ImagePro) Encode() ([]byte, error) { 14 | extension := i.extension 15 | var buff bytes.Buffer 16 | var err error 17 | if extension == "png" { 18 | err = png.Encode(&buff, i.image) 19 | } else if extension == "jpg" || extension == "jpeg" { 20 | quality := 0 21 | if i.opts.Quality != nil { 22 | quality = i.opts.Quality.(int) 23 | } 24 | if quality > 0 { 25 | err = jpeg.Encode(&buff, i.image, &jpeg.Options{Quality: quality}) 26 | } else { 27 | err = jpeg.Encode(&buff, i.image, &jpeg.Options{Quality: 100}) 28 | } 29 | } else if extension == "tiff" { 30 | err = tiff.Encode(&buff, i.image, &tiff.Options{Compression: tiff.Deflate, Predictor: true}) 31 | } else if extension == "bmp" { 32 | err = bmp.Encode(&buff, i.image) 33 | } else if extension == "webp" { 34 | err := webp.Encode(&buff, i.image, &webp.Options{ 35 | Quality: float32(i.opts.Quality.(int)), 36 | Lossless: i.Lossless, 37 | Exact: i.Exact, 38 | }) 39 | if err != nil { 40 | log.Panic(err) 41 | } 42 | } 43 | return buff.Bytes(), err 44 | } 45 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: deps clear_bin build_server_darwin_arm build_server_linux_amd64 build_m3u8_server_darwin_arm build_m3u8_server_linux_amd64 cp_config test 2 | 3 | deps: FORCE 4 | CGO_CFLAGS_ALLOW=-Xpreprocessor go get ./... 5 | clear_bin: FORCE 6 | rm -rf ./bin && mkdir -p bin 7 | build_server_darwin_arm: FORCE 8 | CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 CGO_CFLAGS_ALLOW=-Xpreprocessor go build -o ./bin/server_darwin_arm64 ./cmd/server/main.go 9 | build_server_linux_amd64: FORCE 10 | CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ CGO_CFLAGS_ALLOW=-Xpreprocessor go build -o ./bin/server_linux_amd64 ./cmd/server/main.go 11 | build_m3u8_server_darwin_arm: FORCE 12 | CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 CGO_CFLAGS_ALLOW=-Xpreprocessor go build -o ./bin/m3u8_server_darwin_arm64 ./cmd/m3u8-server/main.go 13 | build_m3u8_server_linux_amd64: FORCE 14 | CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC=x86_64-linux-musl-gcc CXX=x86_64-linux-musl-g++ CGO_CFLAGS_ALLOW=-Xpreprocessor go build -o ./bin/m3u8_server_linux_amd64 ./cmd/m3u8-server/main.go 15 | cp_config: FORCE 16 | cp config.example.yml ./bin/config.yml && cp readme.md ./bin/readme.md && cp image-pro.conf ./bin/image-pro.conf && cp nginx.conf ./bin/nginx.conf 17 | test: FORCE 18 | CGO_CFLAGS_ALLOW=-Xpreprocessor go test -v ./... 19 | FORCE: -------------------------------------------------------------------------------- /src/image-pro/transform.go: -------------------------------------------------------------------------------- 1 | package imagepro 2 | 3 | import ( 4 | "bytes" 5 | "github.com/chai2010/webp" 6 | "github.com/fishtailstudio/imgo" 7 | "log" 8 | ) 9 | 10 | func (i *ImagePro) Transform() *ImagePro { 11 | img := imgo.Load(i.image) 12 | if i.extension == "png" { 13 | i.Lossless = true 14 | i.Exact = true 15 | } 16 | if i.opts.Flip != nil { 17 | img = img.Flip(imgo.FlipType(i.opts.Flip.(int))) 18 | } 19 | if i.opts.Rotate != nil { 20 | img = img.Rotate(i.opts.Flip.(int)) 21 | } 22 | if i.opts.Pixelate != nil { 23 | img = img.Pixelate(i.opts.Pixelate.(int)) 24 | } 25 | switch i.opts.Mode { 26 | case "crop": 27 | img = img.Crop(i.opts.X, i.opts.Y, i.opts.Width, i.opts.Height) 28 | break 29 | case "resize": 30 | img = img.Resize(i.opts.Width, i.opts.Height) 31 | break 32 | case "thumbnail": 33 | img = img.Thumbnail(i.opts.Width, i.opts.Height) 34 | break 35 | default: 36 | break 37 | } 38 | if i.opts.Format == "webp" { 39 | var buff bytes.Buffer 40 | err := webp.Encode(&buff, img.ToImage(), &webp.Options{ 41 | Lossless: i.Lossless, 42 | Exact: i.Exact, 43 | Quality: float32(i.opts.Quality.(int)), 44 | }) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | 49 | webpImg, err := webp.Decode(&buff) 50 | if err != nil { 51 | log.Println("webp编码失败") 52 | log.Panic(err) 53 | } 54 | i.image = webpImg 55 | i.extension = "webp" 56 | } else { 57 | i.image = img.ToImage() 58 | } 59 | return i 60 | } 61 | -------------------------------------------------------------------------------- /src/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/wxnacy/wgo/arrays" 5 | "io" 6 | "log" 7 | "os" 8 | "path" 9 | ) 10 | 11 | func IsImage(ext string) bool { 12 | includes := []string{"jpg", "jpeg", "png", "webp", "bmp", "tiff"} 13 | index := arrays.ContainsString(includes, ext) 14 | if index == -1 { 15 | return false 16 | } 17 | return true 18 | } 19 | func AppPath(elem ...string) string { 20 | rootPath, err := os.Getwd() 21 | if err != nil { 22 | log.Fatal("路径获取失败!¬") 23 | } 24 | return path.Join(rootPath, path.Join(elem...)) 25 | } 26 | 27 | func DataPath(elem ...string) string { 28 | dataPath := GetConfig().Server.DataPath 29 | if dataPath == "" { 30 | return AppPath("data", path.Join(elem...)) 31 | } 32 | return path.Join(dataPath, path.Join(elem...)) 33 | } 34 | func MakeDir(dir string) { 35 | if IsExist(dir) == false { 36 | err := os.MkdirAll(dir, 0776) 37 | if err != nil { 38 | log.Fatal("文件夹" + dir + "创建失败") 39 | } 40 | } 41 | } 42 | func IsExist(path string) bool { 43 | _, err := os.Stat(path) 44 | return err == nil || os.IsExist(err) 45 | } 46 | func ReadFile(path string) []byte { 47 | fileInfo, err := os.Stat(path) 48 | if err != nil { 49 | log.Fatal("config file err") 50 | } 51 | buffer := make([]byte, fileInfo.Size()) 52 | fileHandler, err := os.Open(path) 53 | if err != nil { 54 | log.Fatal("config file err") 55 | } 56 | _, err = io.ReadFull(fileHandler, buffer) 57 | if err != nil { 58 | log.Fatal("config file err") 59 | } 60 | return buffer 61 | } 62 | -------------------------------------------------------------------------------- /cmd/m3u8-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "github.com/duke-git/lancet/fileutil" 8 | "github.com/xiebinbin/m3u8" 9 | "net/http" 10 | "os" 11 | "s3cache/src/utils" 12 | "s3cache/src/utils/storage" 13 | ) 14 | 15 | func buildM3U8(src string) *bytes.Buffer { 16 | nodes := utils.GetConfig().Server.Nodes 17 | f, err := os.Open(src) 18 | if err != nil { 19 | panic(err) 20 | } 21 | p, _, err := m3u8.DecodeFrom(bufio.NewReader(f), true) 22 | if err != nil { 23 | panic(err) 24 | } 25 | playFile := p.(*m3u8.MediaPlaylist) 26 | for i, segment := range playFile.Segments { 27 | if segment == nil { 28 | break 29 | } 30 | nodeIndex := uint8(i) % uint8(len(nodes)) 31 | node := nodes[nodeIndex] 32 | playFile.Segments[i].URI = node + "file/" + segment.URI + "?bucket=hls-ts" 33 | } 34 | return playFile.Encode() 35 | } 36 | func IndexHandler(w http.ResponseWriter, r *http.Request) { 37 | bucket := "hls-m3u8" 38 | objectName := r.URL.Path 39 | localSrcPath := utils.DataPath("src", bucket, objectName) 40 | fmt.Println("path", localSrcPath) 41 | fmt.Println("scheme", r.URL.Scheme) 42 | if fileutil.IsExist(localSrcPath) == false { 43 | err := storage.DownloadObject(bucket, objectName, localSrcPath) 44 | if err != nil { 45 | return 46 | } 47 | } 48 | w.Header().Set("Content-Type", "text/plain") 49 | w.WriteHeader(200) 50 | _, err := w.Write(buildM3U8(localSrcPath).Bytes()) 51 | if err != nil { 52 | return 53 | } 54 | } 55 | func main() { 56 | http.HandleFunc("/", IndexHandler) 57 | err := http.ListenAndServe(utils.GetConfig().Server.M3u8Address, nil) 58 | if err != nil { 59 | return 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/middlewares/handle-cache.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/gogf/gf/os/gfile" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | imagepro "s3cache/src/image-pro" 10 | "s3cache/src/utils" 11 | "strconv" 12 | "strings" 13 | ) 14 | 15 | func HandleCache() gin.HandlerFunc { 16 | return func(c *gin.Context) { 17 | cachePath := utils.DataPath(c.Request.URL.Path) 18 | if utils.IsExist(cachePath) == false { 19 | baseName := gfile.Basename(cachePath) 20 | baseNameInfo := strings.Split(baseName, ".") 21 | if len(baseNameInfo) > 1 && utils.IsImage(baseNameInfo[1]) { 22 | log.Println("处理图片") 23 | src := c.DefaultQuery("src", "") 24 | bucket := c.DefaultQuery("bucket", "") 25 | srcPath := "" 26 | if bucket != "" { 27 | srcPath = utils.DataPath("src", bucket, src) 28 | } else { 29 | srcPath = utils.DataPath("src", src) 30 | } 31 | format := c.DefaultQuery("f", "") 32 | width, err := strconv.Atoi(c.DefaultQuery("w", "0")) 33 | if err != nil { 34 | return 35 | } 36 | height, err := strconv.Atoi(c.DefaultQuery("h", "0")) 37 | if err != nil { 38 | return 39 | } 40 | mode := c.DefaultQuery("m", "") 41 | log.Println("执行转码@@") 42 | buff, err := imagepro.New(srcPath, &imagepro.Options{ 43 | Format: format, 44 | Mode: mode, 45 | Width: width, 46 | Height: height, 47 | Quality: 85, 48 | }).Transform().Encode() 49 | if err != nil { 50 | log.Println(err) 51 | return 52 | } 53 | if err != nil { 54 | log.Println(err) 55 | return 56 | } 57 | utils.MakeDir(filepath.Dir(cachePath)) 58 | 59 | // 保存处理后文件 60 | f, err := os.Create(cachePath) 61 | if err != nil { 62 | log.Println(err) 63 | return 64 | } 65 | _, err = f.Write(buff) 66 | if err != nil { 67 | log.Println(err) 68 | return 69 | } 70 | err = f.Close() 71 | if err != nil { 72 | log.Println(err) 73 | return 74 | } 75 | } 76 | } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/middlewares/handle-src.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/hex" 6 | "github.com/gin-gonic/gin" 7 | "github.com/gogf/gf/os/gfile" 8 | "s3cache/src/utils" 9 | "s3cache/src/utils/storage" 10 | "strings" 11 | ) 12 | 13 | func HandleSrc(r *gin.Engine) gin.HandlerFunc { 14 | return func(c *gin.Context) { 15 | srcPath := strings.Replace(c.Request.URL.Path, "/file/", "", 1) 16 | // 从远程下载文件 17 | bucket := c.DefaultQuery("bucket", "") 18 | localSrcPath := "" 19 | if bucket != "" { 20 | localSrcPath = utils.DataPath("src", bucket, srcPath) 21 | } else { 22 | // 作为本地使用时 23 | localSrcPath = utils.DataPath("src", srcPath) 24 | } 25 | if utils.IsExist(localSrcPath) == false { 26 | // 将下载过的数据放入redis中 27 | if utils.GetConfig().Server.RemoteEnable == false { 28 | return 29 | } 30 | if bucket == "" { 31 | return 32 | } 33 | err := storage.DownloadObject(bucket, srcPath, utils.DataPath("src", bucket, srcPath)) 34 | if err != nil { 35 | return 36 | } 37 | } 38 | baseName := gfile.Basename(srcPath) 39 | baseNameInfo := strings.Split(baseName, ".") 40 | if len(baseNameInfo) > 1 && utils.IsImage(baseNameInfo[1]) { 41 | format := c.DefaultQuery("f", "") 42 | width := c.DefaultQuery("w", "") 43 | height := c.DefaultQuery("h", "") 44 | mode := c.DefaultQuery("m", "") 45 | if format != "" || width != "" || height != "" { 46 | // 重定向到缓存文件 47 | unionName := baseName + "?w=" + width + "&h=" + height + "&f=" + format + "&m=" + mode 48 | hash := md5.Sum([]byte(unionName)) 49 | hashStr := hex.EncodeToString(hash[:]) 50 | c.Request.URL.Path = "/cache/" + hashStr[0:2] + "/" + hashStr[2:4] + "/" + hashStr + "." + format 51 | c.Request.URL.RawQuery = "src=" + srcPath + "&" + c.Request.URL.RawQuery 52 | r.HandleContext(c) 53 | } 54 | } else { 55 | if bucket != "" { 56 | c.Request.URL.Path = "/src/" + bucket + "/" + srcPath 57 | } else { 58 | c.Request.URL.Path = "/src/" + srcPath 59 | } 60 | c.Request.URL.RawQuery = "" 61 | r.HandleContext(c) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module s3cache 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/chai2010/webp v1.1.1 7 | github.com/duke-git/lancet v1.3.7 8 | github.com/fishtailstudio/imgo v0.0.3 9 | github.com/gin-gonic/gin v1.9.0 10 | github.com/gogf/gf v1.16.9 11 | github.com/minio/minio-go/v7 v7.0.49 12 | github.com/wxnacy/wgo v1.0.4 13 | github.com/xiebinbin/m3u8 v0.11.6 14 | golang.org/x/image v0.5.0 15 | gopkg.in/yaml.v3 v3.0.1 16 | ) 17 | 18 | require ( 19 | github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect 20 | github.com/bytedance/sonic v1.8.2 // indirect 21 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 22 | github.com/dustin/go-humanize v1.0.1 // indirect 23 | github.com/fatih/color v1.14.1 // indirect 24 | github.com/fsnotify/fsnotify v1.6.0 // indirect 25 | github.com/gin-contrib/sse v0.1.0 // indirect 26 | github.com/go-playground/locales v0.14.1 // indirect 27 | github.com/go-playground/universal-translator v0.18.1 // indirect 28 | github.com/go-playground/validator/v10 v10.11.2 // indirect 29 | github.com/goccy/go-json v0.10.0 // indirect 30 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 31 | github.com/google/uuid v1.3.0 // indirect 32 | github.com/gookit/goutil v0.6.6 // indirect 33 | github.com/json-iterator/go v1.1.12 // indirect 34 | github.com/klauspost/compress v1.15.15 // indirect 35 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 36 | github.com/leodido/go-urn v1.2.1 // indirect 37 | github.com/mattn/go-colorable v0.1.13 // indirect 38 | github.com/mattn/go-isatty v0.0.17 // indirect 39 | github.com/minio/md5-simd v1.1.2 // indirect 40 | github.com/minio/sha256-simd v1.0.0 // indirect 41 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 42 | github.com/modern-go/reflect2 v1.0.2 // indirect 43 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect 44 | github.com/pelletier/go-toml/v2 v2.0.6 // indirect 45 | github.com/rs/xid v1.4.0 // indirect 46 | github.com/sirupsen/logrus v1.9.0 // indirect 47 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 48 | github.com/ugorji/go/codec v1.2.10 // indirect 49 | go.opentelemetry.io/otel v1.13.0 // indirect 50 | go.opentelemetry.io/otel/trace v1.13.0 // indirect 51 | golang.org/x/arch v0.2.0 // indirect 52 | golang.org/x/crypto v0.6.0 // indirect 53 | golang.org/x/net v0.7.0 // indirect 54 | golang.org/x/sync v0.1.0 // indirect 55 | golang.org/x/sys v0.5.0 // indirect 56 | golang.org/x/text v0.7.0 // indirect 57 | google.golang.org/protobuf v1.28.1 // indirect 58 | gopkg.in/ini.v1 v1.67.0 // indirect 59 | ) 60 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= 2 | github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= 3 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 6 | github.com/bytedance/sonic v1.8.2 h1:Eq1oE3xWIBE3tj2ZtJFK1rDAx7+uA4bRytozVhXMHKY= 7 | github.com/bytedance/sonic v1.8.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 8 | github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk= 9 | github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU= 10 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 11 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 12 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 13 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4= 14 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= 15 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/duke-git/lancet v1.3.7 h1:rcSvXgPbpBzVyUkIFu1O3xvewstr0EQGRVvFwGPQpzc= 19 | github.com/duke-git/lancet v1.3.7/go.mod h1:Grr6ehF0ig2nRIjeb+NmcxiJ12mkML4XQAx95tlQeJU= 20 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 21 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 22 | github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 23 | github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= 24 | github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= 25 | github.com/fishtailstudio/imgo v0.0.3 h1:IYTP/1IbR/4abHoZbrNPvlOd6pfnQVKkgN/td+R0EcI= 26 | github.com/fishtailstudio/imgo v0.0.3/go.mod h1:CNobwWqHyKV+4G2s9agoz9gQe9+xO8foMJFDE/BezbA= 27 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 28 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 29 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 30 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 31 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 32 | github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= 33 | github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= 34 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 35 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 36 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 37 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 38 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 39 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 40 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 41 | github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= 42 | github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= 43 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 44 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 45 | github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= 46 | github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 47 | github.com/gogf/gf v1.16.9 h1:Q803UmmRo59+Ws08sMVFOcd8oNpkSWL9vS33hlo/Cyk= 48 | github.com/gogf/gf v1.16.9/go.mod h1:8Q/kw05nlVRp+4vv7XASBsMe9L1tsVKiGoeP2AHnlkk= 49 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 50 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 51 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 52 | github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= 53 | github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= 54 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 55 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 56 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 57 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 58 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 59 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 60 | github.com/gookit/goutil v0.6.6 h1:XdvnPocHpKDXA+eykfc/F846Y1V2Vyo3+cV8rfliG90= 61 | github.com/gookit/goutil v0.6.6/go.mod h1:D++7kbQd/6vECyYTxB5tq6AKDIG9ZYwZNhubWJvN9dw= 62 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 63 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 64 | github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= 65 | github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= 66 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 67 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 68 | github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= 69 | github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= 70 | github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 71 | github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 72 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 73 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 74 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 75 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 76 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 77 | github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= 78 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 79 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 80 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 81 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 82 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 83 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 84 | github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= 85 | github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 86 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 87 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 88 | github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= 89 | github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= 90 | github.com/minio/minio-go/v7 v7.0.49 h1:dE5DfOtnXMXCjr/HWI6zN9vCrY6Sv666qhhiwUMvGV4= 91 | github.com/minio/minio-go/v7 v7.0.49/go.mod h1:UI34MvQEiob3Cf/gGExGMmzugkM/tNgbFypNDy5LMVc= 92 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 93 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 94 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 95 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 96 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 97 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 98 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 99 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= 100 | github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= 101 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 102 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 103 | github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= 104 | github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= 105 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 106 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 107 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= 108 | github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= 109 | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 110 | github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= 111 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 112 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 113 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 114 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 115 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 116 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 117 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 118 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 119 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 120 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 121 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 122 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 123 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 124 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 125 | github.com/ugorji/go/codec v1.2.10 h1:eimT6Lsr+2lzmSZxPhLFoOWFmQqwk0fllJJ5hEbTXtQ= 126 | github.com/ugorji/go/codec v1.2.10/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 127 | github.com/wxnacy/wgo v1.0.4 h1:UEkzjlW3pMAXcTUCgMekrCvFYLKKwc0p5GAQrMIphs8= 128 | github.com/wxnacy/wgo v1.0.4/go.mod h1:8hqUwCgvMGgAIr4MLIeFur2YXS/Ns3vbyx5abx0e8iM= 129 | github.com/xiebinbin/m3u8 v0.11.6 h1:5zmBinTVuDO8X/eyHRHci4ThJMLlXnptie6BDyq0jCg= 130 | github.com/xiebinbin/m3u8 v0.11.6/go.mod h1:vWbQJLTS50HTt3fP/5OWMK+ujJ5nXIZU57U74sV2a/U= 131 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 132 | go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg= 133 | go.opentelemetry.io/otel v1.13.0 h1:1ZAKnNQKwBBxFtww/GwxNUyTf0AxkZzrukO8MeXqe4Y= 134 | go.opentelemetry.io/otel v1.13.0/go.mod h1:FH3RtdZCzRkJYFTCsAKDy9l/XYjMdNv6QrkFFB8DvVg= 135 | go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs= 136 | go.opentelemetry.io/otel/trace v1.13.0 h1:CBgRZ6ntv+Amuj1jDsMhZtlAPT6gbyIRdaIzFhfBSdY= 137 | go.opentelemetry.io/otel/trace v1.13.0/go.mod h1:muCvmmO9KKpvuXSf3KKAXXB2ygNYHQ+ZfI5X08d3tds= 138 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 139 | golang.org/x/arch v0.2.0 h1:W1sUEHXiJTfjaFJ5SLo0N6lZn+0eO5gWD1MFeTGqQEY= 140 | golang.org/x/arch v0.2.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 141 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 142 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 143 | golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= 144 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 145 | golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= 146 | golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= 147 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 148 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 149 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 150 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 151 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 152 | golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= 153 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 154 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 155 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 156 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 157 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 158 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 159 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 160 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 161 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 162 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 163 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 164 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 165 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 166 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 167 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 168 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 169 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 170 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 171 | golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= 172 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 173 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 174 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 175 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 176 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 177 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 178 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 179 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 180 | golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= 181 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 182 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 183 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 184 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 185 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 186 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 187 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 188 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 189 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 190 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 191 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 192 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 193 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 194 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 195 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 196 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 197 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 198 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 199 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 200 | --------------------------------------------------------------------------------