├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── env.yml ├── go-fiber ├── Dockerfile ├── Dockerfile copy ├── alidrive │ ├── auth.go │ ├── grequest.go │ ├── init.go │ └── req_bean.go ├── alist.db ├── common │ ├── cron.go │ ├── func.go │ ├── router.go │ └── start.go ├── config │ ├── conf.go │ ├── const.go │ └── database.go ├── devgo ├── env.yml ├── go.mod ├── go.sum ├── log.log ├── main.go ├── models │ └── file.go ├── service │ └── dbhandle.go ├── tools │ └── os.go ├── web │ ├── favicon.ico │ ├── index.html │ └── static │ │ ├── css │ │ ├── about.d5045ef5.css │ │ ├── app.cf45cfa9.css │ │ └── chunk-vendors.c1c96981.css │ │ ├── img │ │ └── alist.bcb68ba0.png │ │ └── js │ │ ├── about.fd268f4e.js │ │ ├── app.50c5b16b.js │ │ └── chunk-vendors.aeace884.js └── ztest │ └── dd.json ├── img ├── demo.png ├── rootid.png └── token.png ├── start.sh └── vue ├── .browserslistrc ├── .env.development ├── .env.production ├── .eslintrc.js ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── alist.png │ └── global.css ├── components │ ├── Files.vue │ ├── Footer.vue │ ├── Header.vue │ ├── NotFound.vue │ ├── Path.vue │ ├── Preview.vue │ └── Readme.vue ├── hooks │ ├── useDownloadUrl.ts │ ├── usePassword.ts │ └── useRefresh.ts ├── main.ts ├── router │ └── index.ts ├── shims-vue.d.ts ├── store │ └── index.ts ├── utils │ ├── api.ts │ ├── base64.ts │ ├── check_update.ts │ ├── const.ts │ ├── copy_clip.ts │ ├── date.ts │ ├── file_size.ts │ ├── get_icon.ts │ ├── get_url.ts │ ├── load_js.ts │ ├── request.ts │ └── version_compare.ts └── views │ ├── About.vue │ └── Home.vue ├── tsconfig.json ├── vue.config.js └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | 15 | *.ipynb 16 | online.yml 17 | env copy.yml 18 | @TEMP -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 佰阅部落 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ALIST 2 | 一款基于go+vue的阿里云盘,支持在线播放视频音乐,在线浏览文档图片。直连地址为阿里云oss,当前不限速,体验友好。 3 | 4 | ## 项目说明 5 | 最近学习go语言的过程中,最大的感触是语法虽少但是上手比较困难,正好看到这个项目,采用前后端分离开发,前端vue+后端go语言用的gin框架。所以,为了让自己掌握go语言,我使用go语言最新的fiber框架重构了后端,前后端都移除了部分功能。 6 | 7 | ## 在线演示地址: 8 | - https://pan.baiyue.one 9 | - 国内DEMO演示2: http://103.40.247.22:3000 [【该机器由茶猫云赞助,2天无理由退款+新购9折优惠】](https://www.chamaoyun.com/?u=D50390) 10 | 11 | ![](img/demo.png) 12 | 13 | ## 部署方法 14 | 15 | **请参考博客文章 https://baiyue.one/archives/1726.html** 16 | 17 | ## 命令说明: 18 | 二进制文件,可直接执行,相当于linux上的普通程序。 19 | ```bash 20 | # 启动 21 | ./alist 22 | # 为保持后台持续运行,使用nohup 23 | nohup ./alist > log.log 2>&1 & 24 | 25 | # 停止服务=终止进程 26 | ps -ef|grep alist | grep -v grep | awk '{print $2}' | xargs kill -9 27 | ``` 28 | 29 | ## 参考项目 30 | - https://github.com/Xhofe/alist 31 | 32 | ## 其他自研开源程序 33 | - 佰阅发卡 https://github.com/Baiyuetribe/kamiFaka 34 | - 短视频去水印解析glink https://github.com/Baiyuetribe/glink -------------------------------------------------------------------------------- /env.yml: -------------------------------------------------------------------------------- 1 | info: 2 | title: 阿里云盘List 3 | logo: "此处为logo的url地址" 4 | footer_text: "" 5 | footer_url: "" 6 | music_img: "" 7 | check_update: false 8 | script: "" 9 | autoplay: false 10 | preview: 11 | url: "" 12 | pre_process: [] 13 | extensions: [] 14 | text: [] 15 | max_size: 0 16 | server: 17 | port: "" 18 | search: false 19 | static: "" 20 | password: "" 21 | ali_drive: 22 | api_url: https://api.aliyundrive.com/v2 23 | root_folder: "此处更换为文件夹ID,浏览器地址栏末尾的一段数字就是" 24 | access_token: "" 25 | refresh_token: "此处填写token值" 26 | max_files_count: 3000 27 | database: 28 | type: "" 29 | user: "" 30 | password: "" 31 | host: "" 32 | port: 0 33 | name: "" 34 | tablePrefix: "" 35 | -------------------------------------------------------------------------------- /go-fiber/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM golang:latest as builder 3 | 4 | WORKDIR /build 5 | 6 | COPY . . 7 | 8 | RUN go build -ldflags="-s -w" -o alist 9 | 10 | # upx 压缩 11 | FROM hairyhenderson/upx:latest as upx 12 | # 文件拷贝 13 | COPY --from=builder /build/alist /usr/bin/alist 14 | 15 | RUN upx --best --lzma /usr/bin/alist 16 | 17 | FROM scratch 18 | WORKDIR / 19 | 20 | COPY --from=upx /usr/bin/alist alist 21 | # 目录复制 22 | COPY --from=builder /build/dist ./dist 23 | COPY --from=builder /build/env.yml ./env.yml 24 | 25 | EXPOSE 3000 26 | 27 | ENTRYPOINT [ "/alist" ] 28 | 29 | # # build stage 30 | # FROM alpine:3.7 as build 31 | 32 | # ARG WRK_VERSION=4.0.2 33 | 34 | # RUN apk add --no-cache --virtual .build-deps \ 35 | # build-base \ 36 | # perl \ 37 | # && wget -O /tmp/wrk.tar.gz https://github.com/wg/wrk/archive/${WRK_VERSION}.tar.gz \ 38 | # && tar -xzf /tmp/wrk.tar.gz -C /tmp/ \ 39 | # && make -C /tmp/wrk-${WRK_VERSION} \ 40 | # && mv /tmp/wrk-${WRK_VERSION}/wrk /wrk 41 | 42 | # # upx stage 43 | # FROM gruebel/upx:latest as upx 44 | 45 | # COPY --from=build /wrk /wrk.org 46 | 47 | # RUN upx --best --lzma -o /wrk /wrk.org 48 | 49 | # # final stage 50 | # FROM alpine:3.7 51 | 52 | # ARG BUILD_DATE 53 | 54 | # LABEL org.label-schema.build-date=${BUILD_DATE} \ 55 | # org.label-schema.schema-version="1.0" 56 | 57 | # RUN apk add --no-cache \ 58 | # libgcc 59 | 60 | # COPY --from=upx /wrk /usr/bin/wrk 61 | 62 | # ENTRYPOINT ["wrk"] 63 | 64 | # docker run --rm gruebel/wrk:latest -t2 -c200 -d10s https://www.example.com 65 | 66 | # -c, --connections: total number of HTTP connections to keep open with 67 | # each thread handling N = connections/threads 68 | 69 | # -d, --duration: duration of the test, e.g. 2s, 2m, 2h 70 | 71 | # -t, --threads: total number of threads to use 72 | 73 | # -s, --script: LuaJIT script, see SCRIPTING 74 | 75 | # -H, --header: HTTP header to add to request, e.g. "User-Agent: wrk" 76 | 77 | # --latency: print detailed latency statistics 78 | 79 | # --timeout: record a timeout if a response is not received within 80 | # this amount of time. -------------------------------------------------------------------------------- /go-fiber/Dockerfile copy: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | WORKDIR /bin 3 | 4 | COPY ./alist ./alist 5 | # 目录复制 6 | COPY ./dist ./dist 7 | COPY ./env.yml ./env.yml 8 | 9 | EXPOSE 3000 10 | 11 | ENTRYPOINT [ "alist" ] 12 | # CMD [ "./alist" ] 13 | 14 | # # build stage 15 | # FROM alpine:3.7 as build 16 | 17 | # ARG WRK_VERSION=4.0.2 18 | 19 | # RUN apk add --no-cache --virtual .build-deps \ 20 | # build-base \ 21 | # perl \ 22 | # && wget -O /tmp/wrk.tar.gz https://github.com/wg/wrk/archive/${WRK_VERSION}.tar.gz \ 23 | # && tar -xzf /tmp/wrk.tar.gz -C /tmp/ \ 24 | # && make -C /tmp/wrk-${WRK_VERSION} \ 25 | # && mv /tmp/wrk-${WRK_VERSION}/wrk /wrk 26 | 27 | # # upx stage 28 | # FROM gruebel/upx:latest as upx 29 | 30 | # COPY --from=build /wrk /wrk.org 31 | 32 | # RUN upx --best --lzma -o /wrk /wrk.org 33 | 34 | # # final stage 35 | # FROM alpine:3.7 36 | 37 | # ARG BUILD_DATE 38 | 39 | # LABEL org.label-schema.build-date=${BUILD_DATE} \ 40 | # org.label-schema.schema-version="1.0" 41 | 42 | # RUN apk add --no-cache \ 43 | # libgcc 44 | 45 | # COPY --from=upx /wrk /usr/bin/wrk 46 | 47 | # ENTRYPOINT ["wrk"] 48 | 49 | # docker run --rm gruebel/wrk:latest -t2 -c200 -d10s https://www.example.com 50 | 51 | # -c, --connections: total number of HTTP connections to keep open with 52 | # each thread handling N = connections/threads 53 | 54 | # -d, --duration: duration of the test, e.g. 2s, 2m, 2h 55 | 56 | # -t, --threads: total number of threads to use 57 | 58 | # -s, --script: LuaJIT script, see SCRIPTING 59 | 60 | # -H, --header: HTTP header to add to request, e.g. "User-Agent: wrk" 61 | 62 | # --latency: print detailed latency statistics 63 | 64 | # --timeout: record a timeout if a response is not received within 65 | # this amount of time. -------------------------------------------------------------------------------- /go-fiber/alidrive/auth.go: -------------------------------------------------------------------------------- 1 | package alidrive 2 | 3 | import ( 4 | "alist/config" 5 | "alist/models" 6 | "fmt" 7 | "io/ioutil" 8 | 9 | "github.com/levigross/grequests" 10 | 11 | "gopkg.in/yaml.v2" 12 | ) 13 | 14 | func GetUserInfo() { 15 | url := config.Conf.AliDrive.ApiUrl + "/user/get" 16 | res := Post(url, map[string]string{}) 17 | // fmt.Println(res) 18 | if err := res.JSON(&User); err != nil { 19 | panic(err) 20 | } 21 | // fmt.Println(User) // 平时打印效果为值,没有key 22 | // fmt.Println(User.Phone) 23 | } 24 | 25 | // 获取jwt-token 26 | func RefreshToken(token string) bool { 27 | // 刷新tokne 28 | url := "https://auth.aliyundrive.com/v2/account/token" 29 | // fmt.Println(token, url) 30 | res, err := grequests.Post(url, &grequests.RequestOptions{ 31 | JSON: map[string]string{"refresh_token": token, "grant_type": "refresh_token"}, 32 | }) 33 | if err != nil { 34 | fmt.Println("请求出错") 35 | return false 36 | } 37 | // fmt.Println(res.String()) 38 | type Item struct { 39 | AccessToken string `json:"access_token"` 40 | RefreshToken string `json:"refresh_token"` 41 | } 42 | itmes := new(Item) 43 | // fmt.Println(res.String()) 44 | if err := res.JSON(&itmes); err != nil { 45 | fmt.Println("The input parameter refresh_token is not valid") 46 | return false 47 | } 48 | config.Conf.AliDrive.AccessToken = itmes.AccessToken // 新值为:=,非新值使用等号= 49 | config.Conf.AliDrive.RefreshToken = itmes.RefreshToken // 新值为:=,非新值使用等号= 50 | config.Authorization = config.Bearer + itmes.AccessToken 51 | if data, err := yaml.Marshal(config.Conf); err != nil { 52 | fmt.Println("解析失败") 53 | return false 54 | } else { 55 | if err := ioutil.WriteFile("env.yml", data, 0777); err != nil { //该操作为全覆盖, 56 | fmt.Println("修改失败") 57 | } 58 | } 59 | return true 60 | } 61 | 62 | type Files struct { 63 | Items []models.File `json:"items"` 64 | NextMarker string `json:"next_marker"` 65 | Readme string `json:"readme"` // Deprecated 66 | Paths []Path `json:"paths"` 67 | } 68 | 69 | type Path struct { 70 | Name string `json:"name"` 71 | FileId string `json:"file_id"` 72 | } 73 | 74 | // list request bean 75 | type ListReq struct { 76 | DriveId string `json:"drive_id"` 77 | Fields string `json:"fields"` 78 | ImageThumbnailProcess string `json:"image_thumbnail_process"` 79 | ImageUrlProcess string `json:"image_url_process"` 80 | Limit int `json:"limit"` 81 | Marker string `json:"marker"` 82 | OrderBy string `json:"order_by"` 83 | OrderDirection string `json:"order_direction"` 84 | ParentFileId string `json:"parent_file_id"` 85 | VideoThumbnailProcess string `json:"video_thumbnail_process"` 86 | } 87 | 88 | func GetList(parent string, limit int, marker string, orderBy string, orderDirection string) *Files { 89 | url := config.Conf.AliDrive.ApiUrl + "/file/list" 90 | // fmt.Println(url) 91 | data := ListReq{ 92 | DriveId: User.DefaultDriveId, 93 | Fields: "*", 94 | ImageThumbnailProcess: config.ImageThumbnailProcess, 95 | ImageUrlProcess: config.ImageUrlProcess, 96 | Limit: limit, 97 | Marker: marker, 98 | OrderBy: orderBy, 99 | OrderDirection: orderDirection, 100 | ParentFileId: parent, 101 | VideoThumbnailProcess: config.VideoThumbnailProcess, 102 | } 103 | var resp Files 104 | res := Post2(url, data) 105 | if err := res.JSON(&resp); err != nil { 106 | fmt.Println(err) 107 | return nil 108 | } 109 | // fmt.Println(resp) 110 | return &resp 111 | } 112 | 113 | type DownloadResp struct { 114 | Expiration string `json:"expiration"` 115 | Method string `json:"method"` 116 | Size int64 `json:"size"` 117 | Url string `json:"url"` 118 | //RateLimit struct{ 119 | // PartSize int `json:"part_size"` 120 | // PartSpeed int `json:"part_speed"` 121 | //} `json:"rate_limit"`//rate limit 122 | } 123 | 124 | // download request bean 125 | type DownloadReq struct { 126 | DriveId string `json:"drive_id"` 127 | FileId string `json:"file_id"` 128 | ExpireSec int `json:"expire_sec"` 129 | FileName string `json:"file_name"` 130 | } 131 | 132 | // get download_url 133 | func GetDownLoadUrl(fileId string) *DownloadResp { 134 | url := config.Conf.AliDrive.ApiUrl + "/file/get_download_url" 135 | data := DownloadReq{ 136 | DriveId: User.DefaultDriveId, 137 | FileId: fileId, 138 | ExpireSec: 14400, 139 | } 140 | var resp DownloadResp 141 | res := Post2(url, data) 142 | if res == nil { 143 | return nil 144 | } 145 | if err := res.JSON(&resp); err != nil { 146 | // fmt.Println(err) 147 | return nil 148 | } 149 | // fmt.Println(resp) 150 | return &resp 151 | } 152 | 153 | // office_preview_url response bean 154 | type OfficePreviewUrlResp struct { 155 | PreviewUrl string `json:"preview_url"` 156 | AccessToken string `json:"access_token"` 157 | } 158 | 159 | // get office preview url and token 160 | func GetOfficePreviewUrl(fileId string) *OfficePreviewUrlResp { 161 | url := config.Conf.AliDrive.ApiUrl + "/file/get_office_preview_url" 162 | // office_preview_url request bean 163 | type OfficePreviewUrlReq struct { 164 | AccessToken string `json:"access_token"` 165 | DriveId string `json:"drive_id"` 166 | FileId string `json:"file_id"` 167 | } 168 | data := OfficePreviewUrlReq{ 169 | AccessToken: config.Conf.AliDrive.AccessToken, 170 | DriveId: User.DefaultDriveId, 171 | FileId: fileId, 172 | } 173 | // fmt.Println(data) 174 | var resp OfficePreviewUrlResp 175 | res := Post2(url, data) 176 | if err := res.JSON(&resp); err != nil { 177 | fmt.Println(err) 178 | } 179 | return &resp 180 | } 181 | -------------------------------------------------------------------------------- /go-fiber/alidrive/grequest.go: -------------------------------------------------------------------------------- 1 | package alidrive 2 | 3 | import ( 4 | "alist/config" 5 | 6 | "github.com/levigross/grequests" 7 | ) 8 | 9 | func Post(url string, data map[string]string) *grequests.Response { 10 | res, err := grequests.Post(url, &grequests.RequestOptions{ 11 | JSON: data, 12 | Headers: map[string]string{ 13 | "Content-Type": "application/json", 14 | "Origin": "https://aliyundrive.com", 15 | "authorization": config.Authorization, 16 | }, 17 | UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", 18 | }) 19 | if err != nil { 20 | // panic(err) 21 | return nil 22 | } 23 | return res 24 | } 25 | 26 | func Post2(url string, data interface{}) *grequests.Response { 27 | res, err := grequests.Post(url, &grequests.RequestOptions{ 28 | JSON: data, 29 | Headers: map[string]string{ 30 | "Content-Type": "application/json", 31 | "Origin": "https://www.aliyundrive.com", 32 | "Accept": "application/json, text/plain, */*", 33 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7", 34 | "Connection": "keep-alive", 35 | "authorization": config.Conf.AliDrive.AccessToken, 36 | }, 37 | UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", 38 | }) 39 | if err != nil { 40 | // panic(err) 41 | return nil 42 | } 43 | // fmt.Println(res.StatusCode) 44 | 45 | // fmt.Println(res.String()) 46 | return res 47 | } 48 | -------------------------------------------------------------------------------- /go-fiber/alidrive/init.go: -------------------------------------------------------------------------------- 1 | package alidrive 2 | 3 | import ( 4 | "alist/config" 5 | "fmt" 6 | ) 7 | 8 | func InitAliDrive() bool { 9 | // 初始化阿里云 10 | if config.Conf.AliDrive.RefreshToken == "" { 11 | // 重新获取 12 | panic("token无效,请重新设置env.yml") 13 | } else { 14 | if !RefreshToken(config.Conf.AliDrive.RefreshToken) { 15 | fmt.Println("token更新失败") 16 | return false 17 | } 18 | fmt.Println("token更新成功") 19 | } 20 | // 更新状态---- 21 | // fmt.Println("请求头", config.Authorization) 22 | // 初始化用户信息 23 | GetUserInfo() // 更新User信息--ok 24 | // fmt.Println(res.String()) 25 | return true 26 | } 27 | -------------------------------------------------------------------------------- /go-fiber/alidrive/req_bean.go: -------------------------------------------------------------------------------- 1 | package alidrive 2 | 3 | // 定义请求所需的表 4 | 5 | type UserInfo struct { 6 | DomainId string `json:"domain_id"` 7 | UserId string `json:"user_id"` 8 | Avatar string `json:"avatar"` 9 | CreatedAt int64 `json:"created_at"` 10 | UpdatedAt int64 `json:"updated_at"` 11 | Email string `json:"email"` 12 | NickName string `json:"nick_name"` 13 | Phone string `json:"phone"` 14 | Role string `json:"role"` 15 | Status string `json:"status"` 16 | UserName string `json:"user_name"` 17 | Description string `json:"description"` 18 | DefaultDriveId string `json:"default_drive_id"` 19 | UserData map[string]interface{} `json:"user_data"` 20 | } 21 | 22 | // 定义用户信息 23 | var User *UserInfo 24 | -------------------------------------------------------------------------------- /go-fiber/alist.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baiyuetribe/alist_fiber/270ea9f1013ff6be0d104095bf5776a17a336ac1/go-fiber/alist.db -------------------------------------------------------------------------------- /go-fiber/common/cron.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "alist/alidrive" 5 | "alist/config" 6 | "fmt" 7 | 8 | "github.com/robfig/cron/v3" //定时任务 9 | ) 10 | 11 | var Cron *cron.Cron // 未定义前,无法直接使用 12 | 13 | func refreshToken() { 14 | alidrive.RefreshToken(config.Conf.AliDrive.RefreshToken) // 更新token获取accessToken---ok 15 | config.Authorization = config.Bearer + config.Conf.AliDrive.AccessToken 16 | } 17 | 18 | func InitCron() { 19 | Cron = cron.New() 20 | // _, err := Cron.AddFunc("@every 10s", refreshToken) 21 | _, err := Cron.AddFunc("@every 2h", refreshToken) 22 | if err != nil { 23 | fmt.Println("添加定时任务失败", err) 24 | } 25 | Cron.Start() 26 | } 27 | -------------------------------------------------------------------------------- /go-fiber/common/func.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "alist/alidrive" 5 | "alist/config" 6 | "alist/service" 7 | "fmt" 8 | "net/url" 9 | "path/filepath" 10 | 11 | "github.com/gofiber/fiber/v2" 12 | "github.com/levigross/grequests" 13 | ) 14 | 15 | func Info(c *fiber.Ctx) error { 16 | return c.JSON(fiber.Map{"meta": fiber.Map{"code": 200, "msg": "success"}, "data": config.Conf.Info}) 17 | } 18 | 19 | func Info2(c *fiber.Ctx) error { 20 | type Info struct { 21 | Url string `json:"url"` 22 | Origin string `json:"origin"` 23 | } 24 | res, err := grequests.Post("http://httpbin.org/post", &grequests.RequestOptions{ 25 | Data: map[string]string{"name": "lili", "password": "deded"}, 26 | Headers: map[string]string{ 27 | "Content-Type": "application/json", 28 | "Origin": "https://aliyundrive.com", 29 | }, 30 | UserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", 31 | }) 32 | if err != nil { 33 | fmt.Println("请求错误") 34 | } 35 | fmt.Println(res.StatusCode) 36 | fmt.Println(res.String()) 37 | fmt.Println(res.JSON(map[string]string{})) 38 | return c.SendString("你好info") 39 | } 40 | 41 | func Get(c *fiber.Ctx) error { 42 | type GetReq struct { 43 | Path string `json:"path" binding:"required"` 44 | Password string `json:"password"` 45 | } 46 | var get GetReq 47 | if err := c.BodyParser(&get); err != nil { 48 | return c.Status(400).JSON(fiber.Map{"msg": "miss data"}) 49 | } 50 | dir, name := filepath.Split(get.Path) 51 | file := service.GetFileByDirAndName(dir, name) 52 | if file == nil { 53 | return c.Status(400).JSON(fiber.Map{"msg": "path not found", "code": 400}) 54 | } 55 | down := alidrive.GetDownLoadUrl(file.FileID) 56 | if down == nil { 57 | return c.Status(500).JSON(fiber.Map{"msg": "失败"}) 58 | } 59 | // c.JSON(200, DataResponse(down)) // 待解决 60 | return c.JSON(fiber.Map{"meta": fiber.Map{"code": 200, "msg": "success"}, "data": down}) 61 | } 62 | 63 | func Path(c *fiber.Ctx) error { 64 | type PathItem struct { 65 | Path string `json:"path" binding:"required"` 66 | Password string `json:"password"` 67 | } 68 | var res PathItem // res := new(PathItem) 69 | if err := c.BodyParser(&res); err != nil { 70 | return c.Status(400).JSON(fiber.Map{"msg": "miss data"}) 71 | } 72 | // 执行models 73 | dir, name := filepath.Split(res.Path) 74 | // fmt.Println(dir, name, "外部函数") 75 | file := service.GetFileByDirAndName(dir, name) 76 | // if file == nil { 77 | // return c.JSON(fiber.Map{"msg": "path not found"}) 78 | // } 79 | // 处理单个文件 80 | if file.Type == "file" { 81 | return c.JSON(fiber.Map{"meta": fiber.Map{"code": 200, "msg": "success"}, "data": file}) 82 | } 83 | // 处理文件夹 84 | files, err := service.GetFilesByDir(res.Path + "/") 85 | if err != nil { 86 | return c.Status(500).JSON(fiber.Map{"msg": err.Error()}) 87 | } 88 | // for i,_ := range *files{ 89 | 90 | // } 91 | return c.JSON(fiber.Map{"meta": fiber.Map{"code": 200, "msg": "success"}, "data": files}) 92 | } 93 | 94 | func OfficePreview(c *fiber.Ctx) error { 95 | type OfficePreviewReq struct { 96 | FileId string `json:"file_id" binding:"required"` 97 | } 98 | var req OfficePreviewReq 99 | if err := c.BodyParser(&req); err != nil { 100 | return c.Status(400).JSON(fiber.Map{"msg": "miss data"}) 101 | } 102 | preview := alidrive.GetOfficePreviewUrl(req.FileId) 103 | return c.JSON(fiber.Map{"meta": fiber.Map{"code": 200, "msg": "success"}, "data": preview}) 104 | } 105 | 106 | func LocalSearch(c *fiber.Ctx) error { 107 | return c.SendString("你好local") 108 | } 109 | 110 | func GlobleSearch(c *fiber.Ctx) error { 111 | return c.SendString("你好gbs") 112 | } 113 | 114 | func BackHome(c *fiber.Ctx) error { 115 | return c.Redirect("/") 116 | } 117 | 118 | func Rebuild(c *fiber.Ctx) error { 119 | password := c.Params("password") 120 | if password != config.Conf.Server.Password { 121 | return c.JSON(fiber.Map{"msg": "wrong password."}) 122 | } 123 | if err := service.Clear(); err != nil { 124 | return c.Status(500).JSON(fiber.Map{"msg": err.Error()}) 125 | } 126 | if err := service.BuildTree(); err != nil { 127 | return c.Status(500).JSON(fiber.Map{"msg": err.Error()}) 128 | } 129 | return c.JSON(fiber.Map{"code": 200, "msg": "success"}) 130 | } 131 | 132 | func Down(c *fiber.Ctx) error { 133 | // filePath := c.Params("file") 134 | filePath, _ := url.QueryUnescape(c.Params("*")) 135 | // type DownReq struct { 136 | // Password string `form:"pw"` 137 | // } 138 | // var down DownReq 139 | dir, name := filepath.Split(filePath) 140 | fileModel := service.GetFileByDirAndName(dir, name) 141 | if fileModel == nil { 142 | return c.Status(404).JSON(fiber.Map{"msg": "not found", "code": 404}) 143 | } 144 | // if fileModel.Password != "" && fileModel.Password != down.Password { 145 | // if down.Password == "" { 146 | // return c.JSON(fiber.Map{"msg": "need password"}) 147 | // } else { 148 | // return c.JSON(fiber.Map{"msg": "wrong password"}) 149 | // } 150 | // } 151 | if fileModel.Type == "folder" { 152 | return c.JSON(fiber.Map{"msg": "无法下载目录"}) 153 | } 154 | file := alidrive.GetDownLoadUrl(fileModel.FileID) 155 | if file == nil { 156 | return c.JSON(fiber.Map{"msg": "下载出错"}) 157 | } 158 | // fmt.Println(file.Url) 159 | return c.Status(301).Redirect(file.Url) 160 | } 161 | -------------------------------------------------------------------------------- /go-fiber/common/router.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "github.com/gofiber/fiber/v2" 4 | 5 | func Router(app *fiber.App) { 6 | // 静态文件目录 7 | app.Static("/", "web") // 以主程序的路径为根目录 8 | // api接口 9 | api := app.Group("/api") 10 | { 11 | api.Get("/info", Info) 12 | api.Post("/get", Get) 13 | api.Post("/path", Path) 14 | api.Post("/office_preview", OfficePreview) 15 | // api.Post("/local_search", LocalSearch) 16 | // api.Post("/globle_search", GlobleSearch) 17 | api.Get("/rebuild/:password", Rebuild) 18 | } 19 | app.Get("/d/*", Down) 20 | app.Get("/root/*", BackHome) 21 | } 22 | -------------------------------------------------------------------------------- /go-fiber/common/start.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "alist/alidrive" 5 | "alist/config" 6 | "alist/service" 7 | "alist/tools" 8 | "flag" 9 | "fmt" 10 | "io/ioutil" 11 | 12 | "gopkg.in/yaml.v2" 13 | ) 14 | 15 | // 初始化参数---自动执行 16 | func init() { 17 | flag.StringVar(&config.Conf.AliDrive.ApiUrl, "api", "https://api.aliyundrive.com/v2", "config api") // 定义配置文件名称 18 | } 19 | 20 | func Start() bool { 21 | printLogo() 22 | // 检查配置文件 23 | if !ReadConf("env.yml") { // >>config.yml---此操作同时更新基础配置文件里的内容到config配置里 24 | return false 25 | } 26 | // 初始化阿里云 27 | if !alidrive.InitAliDrive() { 28 | return false 29 | } 30 | // config.Authorization = config.Bearer + config.Conf.AliDrive.AccessToken 31 | // 初始化数据库--首次就完成 32 | config.InitDB() 33 | if err := service.Clear(); err != nil { 34 | fmt.Println("清空历史记录失败") 35 | } 36 | // 构建目录树 37 | if err := service.BuildTree(); err != nil { 38 | fmt.Println("构建目录树失败") 39 | return false 40 | } 41 | fmt.Println("初始化完成") 42 | // 初始化定时任务 43 | InitCron() 44 | // 运行服务 45 | return true 46 | } 47 | 48 | // func InitModel() { 49 | // needMigrate := !tools.Exists("alist.db") 50 | // fmt.Println(needMigrate) 51 | // if needMigrate { 52 | // database.InitDB() 53 | // } 54 | // } 55 | 56 | // read config file 57 | func ReadConf(name string) bool { 58 | // fmt.Println("读取配置文件...") 59 | if !tools.Exists(name) { 60 | fmt.Println("找不到配置文件:", name) 61 | return false 62 | } 63 | 64 | confFile, err := ioutil.ReadFile(name) // 文件读取 65 | if err != nil { 66 | fmt.Println("读取配置文件时发生错误:", err.Error()) 67 | return false 68 | } 69 | // 此处从外围调用 70 | err = yaml.Unmarshal(confFile, config.Conf) // 入口字节,出口{} 71 | if err != nil { 72 | fmt.Printf("加载配置文件时发生错误:%s", err.Error()) 73 | return false 74 | } 75 | return true 76 | } 77 | 78 | func printLogo() { 79 | fmt.Print(` 80 | 81 | ██████╗ █████╗ ██╗██╗ ██╗██╗ ██╗███████╗ 82 | ██╔══██╗██╔══██╗██║╚██╗ ██╔╝██║ ██║██╔════╝ 83 | ██████╔╝███████║██║ ╚████╔╝ ██║ ██║█████╗ 84 | ██╔══██╗██╔══██║██║ ╚██╔╝ ██║ ██║██╔══╝ 85 | ██████╔╝██║ ██║██║ ██║ ╚██████╔╝███████╗ 86 | ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝ 87 | 88 | 89 | 90 | `) 91 | } 92 | -------------------------------------------------------------------------------- /go-fiber/config/conf.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // config struct 4 | type Config struct { 5 | Info struct { 6 | Title string `yaml:"title" json:"title"` 7 | Logo string `yaml:"logo" json:"logo"` 8 | FooterText string `yaml:"footer_text" json:"footer_text"` 9 | FooterUrl string `yaml:"footer_url" json:"footer_url"` 10 | MusicImg string `yaml:"music_img" json:"music_img"` 11 | CheckUpdate bool `yaml:"check_update" json:"check_update"` 12 | Script string `yaml:"script" json:"script"` 13 | Autoplay bool `yaml:"autoplay" json:"autoplay"` 14 | Preview struct { 15 | Url string `yaml:"url" json:"url"` 16 | PreProcess []string `yaml:"pre_process" json:"pre_process"` 17 | Extensions []string `yaml:"extensions" json:"extensions"` 18 | Text []string `yaml:"text" json:"text"` 19 | MaxSize int `yaml:"max_size" json:"max_size"` 20 | } `yaml:"preview" json:"preview"` 21 | } `yaml:"info"` 22 | Server struct { 23 | Port string `yaml:"port"` //端口 24 | Search bool `yaml:"search"` //允许搜索 25 | Static string `yaml:"static"` 26 | // SiteUrl string `yaml:"site_url"` //网站url 27 | Password string `yaml:"password"` 28 | } `yaml:"server"` 29 | AliDrive struct { 30 | ApiUrl string `yaml:"api_url"` //阿里云盘api 31 | RootFolder string `yaml:"root_folder"` //根目录id 32 | //Authorization string `yaml:"authorization"`//授权token 33 | // LoginToken string `yaml:"login_token"` 34 | AccessToken string `yaml:"access_token"` 35 | RefreshToken string `yaml:"refresh_token"` 36 | MaxFilesCount int `yaml:"max_files_count"` 37 | } `yaml:"ali_drive"` 38 | Database struct { 39 | Type string `yaml:"type"` 40 | User string `yaml:"user"` 41 | Password string `yaml:"password"` 42 | Host string `yaml:"host"` 43 | Port int `yaml:"port"` 44 | Name string `yaml:"name"` 45 | TablePrefix string `yaml:"tablePrefix"` 46 | } `yaml:"database"` 47 | } 48 | -------------------------------------------------------------------------------- /go-fiber/config/const.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | var ( 4 | Version bool // is print version command 5 | // Con string // config file--env.yml 6 | Authorization string // authorization string 7 | ) 8 | 9 | var Conf = new(Config) 10 | 11 | const ( 12 | VERSION = "v1.0.0" 13 | ImageThumbnailProcess = "image/resize,w_50" 14 | VideoThumbnailProcess = "video/snapshot,t_0,f_jpg,w_50" 15 | ImageUrlProcess = "image/resize,w_1920/format,jpeg" 16 | ASC = "ASC" 17 | DESC = "DESC" 18 | OrderUpdatedAt = "updated_at" 19 | OrderCreatedAt = "created_at" 20 | OrderSize = "size" 21 | OrderName = "name" 22 | OrderSearch = "type ASC,updated_at DESC" 23 | AccessTokenInvalid = "AccessTokenInvalid" 24 | Bearer = "Bearer\t" 25 | ) 26 | -------------------------------------------------------------------------------- /go-fiber/config/database.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "alist/models" 5 | "fmt" 6 | 7 | "gorm.io/driver/sqlite" 8 | "gorm.io/gorm" 9 | ) 10 | 11 | var ( 12 | DB *gorm.DB // 先定义,后使用,初始化后值改变,可直接引用 13 | ) 14 | 15 | func InitDB() { 16 | db, err := gorm.Open(sqlite.Open("alist.db"), &gorm.Config{}) // 更新db的值 17 | if err != nil { 18 | panic(err) 19 | } 20 | DB = db //由于先前已赋值,无法再次赋值,需要等号 21 | // 此步骤惯例在这里进行 22 | if err := DB.AutoMigrate(models.File{}); err != nil { 23 | panic(err) 24 | } 25 | 26 | fmt.Println("数据库初始化完成") 27 | } 28 | -------------------------------------------------------------------------------- /go-fiber/devgo: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "alist/common" 5 | "log" 6 | "time" 7 | 8 | "github.com/gofiber/fiber/v2" 9 | "github.com/gofiber/fiber/v2/middleware/cache" 10 | "github.com/gofiber/fiber/v2/middleware/compress" 11 | "github.com/gofiber/fiber/v2/middleware/cors" 12 | "github.com/gofiber/fiber/v2/middleware/etag" 13 | "github.com/gofiber/fiber/v2/middleware/logger" 14 | // "github.com/gofiber/fiber/v2/middleware/monitor" 15 | ) 16 | 17 | func main() { 18 | // 创建实例 19 | app := fiber.New() 20 | app.Use(logger.New()) 21 | app.Use(compress.New()) // 压缩静态资源未gzip或br 22 | app.Use(etag.New()) //一些内容不变的东西,不会重复发送 23 | app.Use(cache.New(cache.Config{ 24 | Expiration: 2 * time.Minute, 25 | })) // 生产环境 缓存一分钟内的请求结果 26 | app.Use(cors.New()) 27 | 28 | common.Start() // 包含数据库初始化 29 | // db := database.GetDB() 30 | // db.Find(&user) 31 | // 初始化路由 32 | common.Router(app) 33 | // app.Get("/dashboard", monitor.New()) // 代码运行监视器,开发环境使用 34 | // 启动 35 | log.Fatal(app.Listen("127.0.0.1:3000")) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-fiber/env.yml: -------------------------------------------------------------------------------- 1 | info: 2 | title: 阿里云盘List 3 | logo: "此处为logo的url地址" 4 | footer_text: "" 5 | footer_url: "" 6 | music_img: "" 7 | check_update: false 8 | script: "" 9 | autoplay: false 10 | preview: 11 | url: "" 12 | pre_process: [] 13 | extensions: [] 14 | text: [] 15 | max_size: 0 16 | server: 17 | port: "" 18 | search: false 19 | static: "" 20 | password: "" 21 | ali_drive: 22 | api_url: https://api.aliyundrive.com/v2 23 | root_folder: "此处更换为文件夹ID,浏览器地址栏末尾的一段数字就是" 24 | access_token: "" 25 | refresh_token: "此处填写token值" 26 | max_files_count: 3000 27 | database: 28 | type: "" 29 | user: "" 30 | password: "" 31 | host: "" 32 | port: 0 33 | name: "" 34 | tablePrefix: "" 35 | -------------------------------------------------------------------------------- /go-fiber/go.mod: -------------------------------------------------------------------------------- 1 | module alist 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gofiber/fiber/v2 v2.5.0 7 | github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a 8 | github.com/robfig/cron/v3 v3.0.1 9 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect 10 | golang.org/x/sys v0.0.0-20210402192133-700132347e07 // indirect 11 | gopkg.in/yaml.v2 v2.4.0 12 | gorm.io/driver/sqlite v1.1.4 13 | gorm.io/gorm v1.21.3 14 | ) 15 | -------------------------------------------------------------------------------- /go-fiber/go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= 2 | github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 3 | github.com/gofiber/fiber/v2 v2.5.0 h1:yml405Um7b98EeMjx63OjSFTATLmX985HPWFfNUPV0w= 4 | github.com/gofiber/fiber/v2 v2.5.0/go.mod h1:f8BRRIMjMdRyt2qmJ/0Sea3j3rwwfufPrh9WNBRiVZ0= 5 | github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= 6 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 7 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 8 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 9 | github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= 10 | github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 11 | github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg= 12 | github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 13 | github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a h1:DGFy/362j92vQRE3ThU1yqg9TuJS8YJOSbQuB7BP9cA= 14 | github.com/levigross/grequests v0.0.0-20190908174114-253788527a1a/go.mod h1:jVntzcUU+2BtVohZBQmSHWUmh8B55LCNfPhcNCIvvIg= 15 | github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= 16 | github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= 17 | github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= 18 | github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= 19 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 20 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 21 | github.com/valyala/fasthttp v1.18.0 h1:IV0DdMlatq9QO1Cr6wGJPVW1sV1Q8HvZXAIcjorylyM= 22 | github.com/valyala/fasthttp v1.18.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A= 23 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc= 24 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= 25 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 26 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 27 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 28 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 29 | golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 30 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= 31 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 32 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 33 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 34 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 35 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 36 | golang.org/x/sys v0.0.0-20201210223839-7e3030f88018/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 37 | golang.org/x/sys v0.0.0-20210402192133-700132347e07 h1:4k6HsQjxj6hVMsI2Vf0yKlzt5lXxZsMW1q0zaq2k8zY= 38 | golang.org/x/sys v0.0.0-20210402192133-700132347e07/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 40 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 41 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 42 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 43 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 44 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 45 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 46 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 47 | gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= 48 | gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= 49 | gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 50 | gorm.io/gorm v1.21.3 h1:qDFi55ZOsjZTwk5eN+uhAmHi8GysJ/qCTichM/yO7ME= 51 | gorm.io/gorm v1.21.3/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= 52 | -------------------------------------------------------------------------------- /go-fiber/log.log: -------------------------------------------------------------------------------- 1 | [23:00:47] 200 - 519.1µs GET /api/info 2 | [23:01:10] 200 - 0s POST /api/path 3 | [23:01:43] 200 - 624.6µs POST /api/path 4 | [23:01:43] 200 - 1.0019ms POST /api/path 5 | [23:01:43] 200 - 999.4µs POST /api/path 6 | [23:01:43] 200 - 529.1µs POST /api/path 7 | [23:01:44] 200 - 529.9µs POST /api/path 8 | [23:01:44] 200 - 520.5µs POST /api/path 9 | [23:01:47] 200 - 0s POST /api/path 10 | [23:09:42] 200 - 0s POST /api/path 11 | [23:11:07] 200 - 1.0008ms POST /api/path 12 | [23:11:13] 200 - 1.028ms POST /api/path 13 | [23:11:18] 200 - 0s POST /api/path 14 | [23:11:22] 200 - 0s POST /api/path 15 | 16 | 17 | docker run -itd -p 8080:3000 -v /dd:/downloads jpillora/cloud-torrent 18 | 19 | 20 | {"items":[{"drive_id":"2168970","domain_id":"bj29","file_id":"604dcd77712b6c0792564c2f9d23f5c0608083b8","name":"佰阅发卡KaMiFAKA功能简介.xmind","type":"file","content_type":"application/octet-stream","created_at":"2021-03-14T08:46:47.675Z","updated_at":"2021-03-14T09:47:36.507Z","file_extension":"xmind","hidden":false,"size":124361,"starred":false,"status":"available","upload_id":"908EA17127AF4196ACDEDD14777576CD","parent_file_id":"604ddb8d95e5567c668a4434be5cc18bac1a55f8","crc64_hash":"13263021142986381322","content_hash":"25CB1170EF6EAF61C00EFC31AC3B1FC0D0AD8D8E","content_hash_name":"sha1","download_url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcd77712b6c0792564c2f9d23f5c0608083b8%2F604dcd77868c34de26374b7699448f7273ef73c2?di=bj29&dr=2168970&f=604dcd77712b6c0792564c2f9d23f5c0608083b8&response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27%25E4%25BD%25B0%25E9%2598%2585%25E5%258F%2591%25E5%258D%25A1KaMiFAKA%25E5%258A%259F%25E8%2583%25BD%25E7%25AE%2580%25E4%25BB%258B.xmind&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=WBqwV2mnvuapCMX1EEfdvXyAbp9Xhsox%2B%2B58t9RKeHQ%3D&x-oss-signature-version=OSS2","url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcd77712b6c0792564c2f9d23f5c0608083b8%2F604dcd77868c34de26374b7699448f7273ef73c2?di=bj29&dr=2168970&f=604dcd77712b6c0792564c2f9d23f5c0608083b8&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=Yp%2FBFx1iTQlFoXxj20vNxtmkl0cl9upBybs%2FrpDCRkA%3D&x-oss-signature-version=OSS2","category":"doc","encrypt_mode":"none","punish_flag":0},{"drive_id":"2168970","domain_id":"bj29","file_id":"604dcdb69055f4a6f3bf483da14658e4e404fe7f","name":"Vue-Essentials-Cheat-Sheet.pdf","type":"file","content_type":"application/pdf","created_at":"2021-03-14T08:47:50.303Z","updated_at":"2021-03-14T09:47:36.505Z","file_extension":"pdf","hidden":false,"size":145848,"starred":false,"status":"available","upload_id":"C0D2C890F70C4F9496445DF096A2933C","parent_file_id":"604ddb8d95e5567c668a4434be5cc18bac1a55f8","crc64_hash":"10811783647620578562","content_hash":"03086A171F26AE8964FF6402E01A418A46AB02C5","content_hash_name":"sha1","download_url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcdb69055f4a6f3bf483da14658e4e404fe7f%2F604dcdb6065e1d9ee5644414a4d810acdbebd79f?di=bj29&dr=2168970&f=604dcdb69055f4a6f3bf483da14658e4e404fe7f&response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27Vue-Essentials-Cheat-Sheet.pdf&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=fEGVrbnz580v01cjZC9e8d7IoOwxJ4D%2BsN1%2BT0SS7ao%3D&x-oss-signature-version=OSS2","url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcdb69055f4a6f3bf483da14658e4e404fe7f%2F604dcdb6065e1d9ee5644414a4d810acdbebd79f?di=bj29&dr=2168970&f=604dcdb69055f4a6f3bf483da14658e4e404fe7f&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=L8JdzxzUm2e1YU96QjieqyFZR7q%2BeEDsDdeNP1IOFdY%3D&x-oss-signature-version=OSS2","category":"doc","encrypt_mode":"none","punish_flag":0},{"drive_id":"2168970","domain_id":"bj29","file_id":"604dcde25d82e7b9a75e48fb9a695b53233fe438","name":"Bootstrap-Cheat-Sheet-websitesetup.org_.pdf","type":"file","content_type":"application/pdf","created_at":"2021-03-14T08:48:34.760Z","updated_at":"2021-03-14T09:47:36.504Z","file_extension":"pdf","hidden":false,"size":817447,"starred":false,"status":"available","upload_id":"FB98EA8EABEE4C4EB62BB4D38E77BF70","parent_file_id":"604ddb8d95e5567c668a4434be5cc18bac1a55f8","crc64_hash":"11015228853740696310","content_hash":"60042B04C2A16D2EF1CDD6DC9F278CAECE59BD9C","content_hash_name":"sha1","download_url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcde25d82e7b9a75e48fb9a695b53233fe438%2F604dcde2de4416692178496fa4ad9b8c2eccb04c?di=bj29&dr=2168970&f=604dcde25d82e7b9a75e48fb9a695b53233fe438&response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27Bootstrap-Cheat-Sheet-websitesetup.org_.pdf&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=e62P%2FRy%2Fo5nvdqRlk9sMWdDesMb4QYn8U6sl%2FkFlEGU%3D&x-oss-signature-version=OSS2","url":"https://bj29.cn-beijing.data.alicloudccp.com/604dcde25d82e7b9a75e48fb9a695b53233fe438%2F604dcde2de4416692178496fa4ad9b8c2eccb04c?di=bj29&dr=2168970&f=604dcde25d82e7b9a75e48fb9a695b53233fe438&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=Y3JQGJ1z%2Bvx6SP6gpoN9L487fjg7%2BT8ybyDmOQROg04%3D&x-oss-signature-version=OSS2","category":"doc","encrypt_mode":"none","punish_flag":0},{"drive_id":"2168970","domain_id":"bj29","file_id":"604dcdb6d3bf6a4e3fbf49938cfbdd5d8c083051","name":"Vue-3-Cheat-Sheet.pdf","type":"file","content_type":"application/pdf","created_at":"2021-03-14T08:47:50.305Z","updated_at":"2021-03-14T09:47:36.504Z","file_extension":"pdf","hidden":false,"size":225607,"starred":false,"status":"available","upload_id":"860E07C1C1B641C9BD179DF478F1A7E2","parent_file_id":"604ddb8d95e5567c668a4434be5cc18bac1a55f8","crc64_hash":"5615391268577353564","content_hash":"6E33CFD8A85E68397741523AB137FA8A7EDF669A","content_hash_name":"sha1","download_url":"https://bj29.cn-beijing.data.alicloudccp.com/5fc5b22c877e0dda2dc240a48ac092dd3b7661b9%2F5fc5b22c727bef2dd0da450380cb23b648ea18e7?di=bj29&dr=2168970&f=604dcdb6d3bf6a4e3fbf49938cfbdd5d8c083051&response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27Vue-3-Cheat-Sheet.pdf&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=GJziLQ3nUG3dLQO2f2byL66%2Bsz6I8aaDUP%2BX4kkmWQ0%3D&x-oss-signature-version=OSS2","url":"https://bj29.cn-beijing.data.alicloudccp.com/5fc5b22c877e0dda2dc240a48ac092dd3b7661b9%2F5fc5b22c727bef2dd0da450380cb23b648ea18e7?di=bj29&dr=2168970&f=604dcdb6d3bf6a4e3fbf49938cfbdd5d8c083051&u=264fd844645e401099addb0f81950b35&x-oss-access-key-id=LTAIsE5mAn2F493Q&x-oss-expires=1616081041&x-oss-signature=P%2BUyj30Q7gzFLZXYFm1nD2grgbl9LcCkVsmjN2mfj8o%3D&x-oss-signature-version=OSS2","category":"doc","encrypt_mode":"none","punish_flag":0}],"next_marker":""}[19:09:50] 200 - 37.4921ms GET / 21 | [19:09:50] 200 - 3.6255ms GET /css/style.css 22 | [19:09:51] 404 - 99.9µs GET /favicon.ico 23 | [19:11:13] 304 - 723.3µs GET / 24 | [19:11:13] 304 - 0s GET / 25 | [19:11:13] 304 - 0s GET / 26 | [19:11:13] 304 - 998.8µs GET / 27 | [19:11:14] 304 - 0s GET / 28 | [19:11:14] 304 - 0s GET / 29 | [19:11:19] 304 - 0s GET / 30 | [19:11:19] 304 - 0s GET / 31 | [19:11:19] 304 - 0s GET / 32 | [19:11:39] 304 - 82.6µs GET / 33 | [19:11:40] 304 - 0s GET / 34 | -------------------------------------------------------------------------------- /go-fiber/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "alist/common" 5 | "log" 6 | 7 | "github.com/gofiber/fiber/v2" 8 | // "github.com/gofiber/fiber/v2/middleware/cache" 9 | "github.com/gofiber/fiber/v2/middleware/compress" 10 | "github.com/gofiber/fiber/v2/middleware/cors" 11 | // "github.com/gofiber/fiber/v2/middleware/logger" 12 | // "github.com/gofiber/fiber/v2/middleware/etag" 13 | // "github.com/gofiber/fiber/v2/middleware/monitor" 14 | ) 15 | 16 | func main() { 17 | // 创建实例 18 | app := fiber.New() 19 | // app.Use(logger.New()) // 开发模式下使用 20 | app.Use(compress.New()) // 压缩静态资源未gzip或br 21 | // app.Use(etag.New()) //一些内容不变的东西,不会重复发送 22 | // app.Use(cache.New(cache.Config{ 23 | // Expiration: 2 * time.Minute, 24 | // })) // 生产环境 缓存一分钟内的请求结果 25 | app.Use(cors.New()) 26 | 27 | common.Start() // 包含数据库初始化 28 | // db := database.GetDB() 29 | // db.Find(&user) 30 | // 初始化路由 31 | common.Router(app) 32 | // app.Get("/dashboard", monitor.New()) // 代码运行监视器,开发环境使用 33 | // 启动 34 | // log.Fatal(app.Listen(":3000")) // linux环境 35 | log.Fatal(app.Listen("127.0.0.1:3000")) // windows环境 36 | 37 | } 38 | -------------------------------------------------------------------------------- /go-fiber/models/file.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "time" 4 | 5 | type File struct { 6 | Dir string `json:"dir" gorm:"index"` 7 | FileExtension string `json:"file_extension"` 8 | FileID string `json:"file_id"` 9 | Name string `json:"name" gorm:"index"` 10 | Type string `json:"type"` 11 | UpdatedAt *time.Time `json:"updated_at"` 12 | Category string `json:"category"` 13 | ContentType string `json:"content_type"` 14 | Size int64 `json:"size"` 15 | Password string `json:"password"` 16 | Url string `json:"url" gorm:"_"` 17 | } 18 | -------------------------------------------------------------------------------- /go-fiber/service/dbhandle.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "alist/alidrive" 5 | "alist/config" 6 | "alist/models" 7 | "fmt" 8 | "strings" 9 | 10 | "gorm.io/gorm" 11 | ) 12 | 13 | func Clear() error { 14 | return config.DB.Where("1 = 1").Delete(&models.File{}).Error 15 | } 16 | 17 | // 创建目录树 18 | func BuildTree() error { 19 | rootFile := models.File{ 20 | Dir: "", 21 | FileID: config.Conf.AliDrive.RootFolder, 22 | Name: "root", 23 | Type: "folder", 24 | } 25 | 26 | if err := config.DB.Create(&rootFile).Error; err != nil { 27 | config.DB.Rollback() 28 | } 29 | 30 | if err := BuildOne(config.Conf.AliDrive.RootFolder, "root/", config.DB, ""); err != nil { 31 | config.DB.Rollback() 32 | fmt.Println("构建失败") 33 | return err 34 | } 35 | return nil 36 | } 37 | 38 | func BuildOne(parent string, path string, tx *gorm.DB, parentPassword string) error { 39 | files := alidrive.GetList(parent, config.Conf.AliDrive.MaxFilesCount, "", "", "") 40 | 41 | if files == nil { 42 | return nil 43 | } 44 | for _, file := range files.Items { 45 | name := file.Name 46 | // fmt.Println(name) 47 | if strings.HasSuffix(name, ".hide") { 48 | continue 49 | } 50 | password := parentPassword 51 | if strings.Contains(name, ".password-") { 52 | index := strings.Index(name, ".password-") 53 | name = file.Name[:index] 54 | password = file.Name[index+10:] 55 | } 56 | newFile := models.File{ 57 | Dir: path, 58 | FileExtension: file.FileExtension, 59 | FileID: file.FileID, 60 | Name: name, 61 | Type: file.Type, 62 | UpdatedAt: file.UpdatedAt, 63 | Category: file.Category, 64 | ContentType: file.ContentType, 65 | Size: file.Size, 66 | Password: password, 67 | } 68 | if err := tx.Create(&newFile).Error; err != nil { 69 | return err 70 | } 71 | if file.Type == "folder" { 72 | if err := BuildOne(file.FileID, fmt.Sprintf("%s%s/", path, name), tx, password); err != nil { 73 | return err 74 | } 75 | } 76 | } 77 | return nil 78 | } 79 | 80 | func GetFileByDirAndName(dir, name string) *models.File { 81 | var file models.File 82 | // fmt.Println(dir, name, "内部函数") 83 | if err := config.DB.Where("dir = ? AND name = ?", dir, name).First(&file).Error; err != nil { 84 | // fmt.Println(err) 85 | // panic(err) 86 | return nil 87 | } 88 | return &file 89 | } 90 | 91 | func GetFilesByDir(dir string) (*[]models.File, error) { 92 | var files []models.File 93 | if err := config.DB.Where("dir = ?", dir).Find(&files).Error; err != nil { 94 | return nil, err 95 | } 96 | return &files, nil 97 | } 98 | -------------------------------------------------------------------------------- /go-fiber/tools/os.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | import "os" 4 | 5 | // 检查文件是否存在 6 | func Exists(name string) bool { 7 | if _, err := os.Stat(name); err != nil { 8 | if os.IsNotExist(err) { 9 | return false 10 | } 11 | } 12 | return true 13 | } 14 | -------------------------------------------------------------------------------- /go-fiber/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baiyuetribe/alist_fiber/270ea9f1013ff6be0d104095bf5776a17a336ac1/go-fiber/web/favicon.ico -------------------------------------------------------------------------------- /go-fiber/web/index.html: -------------------------------------------------------------------------------- 1 | alist-web
-------------------------------------------------------------------------------- /go-fiber/web/static/css/about.d5045ef5.css: -------------------------------------------------------------------------------- 1 | .about[data-v-7d620399]{display:flex;justify-content:flex-start;max-width:min(800px,90vw);margin:20px auto;padding:40px 20px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background-color:hsla(0,0%,100%,.9);border-radius:10px} -------------------------------------------------------------------------------- /go-fiber/web/static/css/app.cf45cfa9.css: -------------------------------------------------------------------------------- 1 | #app,body,html{width:100%;margin:0;padding:0}.ant-input-search,.ant-input-search input{background-color:transparent}.ant-table-row{cursor:pointer}.ant-table td{white-space:nowrap}.ant-table-body::-webkit-scrollbar{width:0!important}.ant-table-body{overflow-x:overlay!important;overflow:-moz-scrollbars-none!important;-ms-overflow-style:none!important}.file-icon[data-v-2f0f65f4]{margin-right:10px;font-size:20px;color:#1890ff}.action[data-v-2f0f65f4]{color:grey}.footer[data-v-7fb59bb1]{width:100%;text-align:center;height:40px}#footer-line[data-v-7fb59bb1]{margin:10px 0}.rebuilding[data-v-7fb59bb1]{margin:0;top:0;right:0;bottom:0;left:0;position:fixed;display:block;background-color:rgba(0,0,0,.7);z-index:2000;text-align:center;padding-top:40vh}.header[data-v-14b649c6]{padding-top:3px;height:56px;width:100%;display:flex;display:-webkit-flex;justify-content:space-between;align-items:center}.header-content[data-v-14b649c6]{margin:10px 0 5px 0}@media screen and (max-width:600px){.qrcode[data-v-14b649c6]{display:none}}.path[data-v-17513f2b]{margin:2px 2px;padding:2px;display:flex;display:-webkit-flex;font-size:20px}.video-preview[data-v-7133190c]{width:100%}.iframe-preview[data-v-7133190c]{width:100%;height:80vh;box-sizing:inherit}.doc-preview[data-v-7133190c],.img-preview[data-v-7133190c]{width:100%;height:80vh}.img-preview img[data-v-7133190c]{max-width:100%;max-height:100%;display:block;margin:auto}.home[data-v-62fb27c4]{justify-content:center}.home-wx[data-v-62fb27c4],.home[data-v-62fb27c4]{width:100%;display:flex;display:-webkit-flex;padding:0;margin:0}.layout[data-v-62fb27c4]{justify-content:center;align-items:center;width:min(980px,98vw)}.content[data-v-62fb27c4],.layout[data-v-62fb27c4]{display:flex;display:-webkit-flex;flex-direction:column}.content[data-v-62fb27c4]{min-height:80vh;width:100%;justify-content:flex-start} -------------------------------------------------------------------------------- /go-fiber/web/static/img/alist.bcb68ba0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baiyuetribe/alist_fiber/270ea9f1013ff6be0d104095bf5776a17a336ac1/go-fiber/web/static/img/alist.bcb68ba0.png -------------------------------------------------------------------------------- /go-fiber/web/static/js/about.fd268f4e.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{"2a25":function(e,t,c){},b6af:function(e,t,c){"use strict";c("2a25")},f820:function(e,t,c){"use strict";c.r(t);var o=c("7a23");const a=Object(o["withScopeId"])("data-v-7d620399");Object(o["pushScopeId"])("data-v-7d620399");const d={class:"about"},n=Object(o["createVNode"])("div",null,[Object(o["createVNode"])("h1",null,[Object(o["createVNode"])("a",{href:"https://github.com/Xhofe/alist"},"Alist")]),Object(o["createVNode"])("p",null,"一款阿里云盘的目录文件列表程序,后端基于go语言fiber框架重构原始项目,前端使用vue和ant design。")],-1);Object(o["popScopeId"])();const s=a((e,t)=>(Object(o["openBlock"])(),Object(o["createBlock"])("div",d,[n])));c("b6af");const b={};b.render=s,b.__scopeId="data-v-7d620399";t["default"]=b}}]); -------------------------------------------------------------------------------- /go-fiber/web/static/js/app.50c5b16b.js: -------------------------------------------------------------------------------- 1 | (function(e){function t(t){for(var n,c,s=t[0],i=t[1],d=t[2],l=0,u=[];l{const s=Object(n["resolveComponent"])("Header"),i=Object(n["resolveComponent"])("Path"),d=Object(n["resolveComponent"])("a-divider"),l=Object(n["resolveComponent"])("Files"),u=Object(n["resolveComponent"])("Readme"),b=Object(n["resolveComponent"])("Preview"),p=Object(n["resolveComponent"])("NotFound"),f=Object(n["resolveComponent"])("Footer"),j=Object(n["resolveComponent"])("a-input-password"),m=Object(n["resolveComponent"])("a-modal");return Object(n["openBlock"])(),Object(n["createBlock"])(n["Fragment"],null,[Object(n["createVNode"])("div",{class:e.isAdrWx?"home-wx":"home"},[Object(n["createVNode"])("div",K,[Object(n["createVNode"])(s),Object(n["createVNode"])("div",Y,[Object(n["createVNode"])("div",J,[Object(n["createVNode"])(i)]),Object(n["createVNode"])(d,{style:{margin:"10px 0 5px 0"}}),"folder"===e.type?(Object(n["openBlock"])(),Object(n["createBlock"])(l,{key:0})):Object(n["createCommentVNode"])("",!0),"folder"===e.type?(Object(n["openBlock"])(),Object(n["createBlock"])(u,{key:1})):Object(n["createCommentVNode"])("",!0),"file"===e.type?(Object(n["openBlock"])(),Object(n["createBlock"])(b,{key:2})):Object(n["createCommentVNode"])("",!0),"no"===e.type?(Object(n["openBlock"])(),Object(n["createBlock"])(p,{key:3})):Object(n["createCommentVNode"])("",!0)]),Object(n["createVNode"])(f)])],2),Object(n["createVNode"])(m,{visible:e.showPassword,"onUpdate:visible":t[2]||(t[2]=t=>e.showPassword=t),title:"Input password",onOk:e.okPassword,onCancel:e.cancelPassword},{default:H(()=>[Object(n["createVNode"])(j,{ref:"inputRef",placeholder:"input password",value:e.password,"onUpdate:value":t[1]||(t[1]=t=>e.password=t),onPressEnter:e.okPassword},null,8,["value","onPressEnter"])]),_:1},8,["visible","onOk","onCancel"])],64)}),G=Object(n["withScopeId"])("data-v-2f0f65f4");Object(n["pushScopeId"])("data-v-2f0f65f4");const X={class:"files"},Q={key:0,class:"action"},Z=Object(n["createVNode"])("br",null,null,-1);Object(n["popScopeId"])();const $=G((e,t,o,c,a,r)=>{const s=Object(n["resolveComponent"])("copy"),i=Object(n["resolveComponent"])("download"),d=Object(n["resolveComponent"])("a-table");return Object(n["openBlock"])(),Object(n["createBlock"])(n["Fragment"],null,[Object(n["createVNode"])("div",X,[Object(n["createVNode"])(d,{columns:e.columns,"data-source":e.files,pagination:!1,rowKey:"file_id",customRow:e.customRow,loading:e.filesLoading,scroll:{x:"max-content"}},{name:G(({text:t,record:o})=>[(Object(n["openBlock"])(),Object(n["createBlock"])(Object(n["resolveDynamicComponent"])(o.icon),{class:"file-icon"})),Object(n["createTextVNode"])(" "+Object(n["toDisplayString"])(t)+" ",1),"file"===o.type?(Object(n["openBlock"])(),Object(n["createBlock"])("span",Q,[Object(n["createVNode"])(s,{id:"action-1",onClick:t=>e.copyFileLink(o)},null,8,["onClick"]),Object(n["createVNode"])("a",{target:"_blank",href:e.getFileDownLink(o)},[Object(n["createVNode"])(i,{class:"action",id:"action-2"})],8,["href"])])):Object(n["createCommentVNode"])("",!0)]),_:1},8,["columns","data-source","customRow","loading"])]),Z],64)});var ee=o("5502");function te(e){if(!e)return"";var t=1024;return e{const s=Object(n["resolveComponent"])("a-divider");return Object(n["openBlock"])(),Object(n["createBlock"])(n["Fragment"],null,[Object(n["createVNode"])(s,{id:"footer-line"}),Object(n["createVNode"])("div",ge,[we,ye,Object(n["createVNode"])(s,{type:"vertical"}),e.info.footer_text?(Object(n["openBlock"])(),Object(n["createBlock"])(s,{key:0,type:"vertical"})):Object(n["createCommentVNode"])("",!0),e.info.footer_text?(Object(n["openBlock"])(),Object(n["createBlock"])("a",{key:1,target:"_blank",href:e.info.footer_url},Object(n["toDisplayString"])(e.info.footer_text),9,["href"])):Object(n["createCommentVNode"])("",!0)])],64)});var Ce=o("bc3a"),xe=o.n(Ce),Ne=xe.a.create({baseURL:"/api/",headers:{"Content-Type":"application/json;charset=utf-8"},withCredentials:!1});Ne.interceptors.request.use((function(e){return e}),(function(e){return console.log("Error: "+e.message),Promise.reject(e)})),Ne.interceptors.response.use((function(e){return e}),(function(e){return console.log(e),e.response&&void 0!=e.response.data.meta?e.response.data:(be["a"].error("后端网络异常,请检查后端程序是否运行或检查网络连接!"),Promise.reject(e))}));var _e=Ne,Se=function(e,t){return _e({url:"get",method:"post",data:{path:e,password:t}})},Be=function(e,t){return _e({url:"path",method:"post",data:{path:e,password:t}})},Ve=function(e,t){return _e({url:"local_search",method:"post",data:{keyword:e,dir:t}})},ze=function(){return _e({url:"info",method:"get"})},Ie=function(e){return _e({url:"rebuild/"+e,method:"get"})},Pe=function(e){return _e({url:"office_preview",method:"post",data:{file_id:e}})},Fe=function(){return xe.a.get("https://api.github.com/repos/Xhofe/alist-web/releases/latest")},Le=function(e){return xe.a.get(e)};function Me(){var e=Object(ee["b"])(),t=Object(A["c"])(),o=function(){e.dispatch("fetchPathOrSearch",{path:decodeURI(t.path.substring(1)),query:t.query["q"]})};return{refresh:o}}var De=Me,Te=Object(n["defineComponent"])({name:"Footer",setup:function(){var e=Object(ee["b"])(),t=Object(n["computed"])((function(){return e.state.info})),o=Object(n["ref"])(!1),c=Object(n["ref"])(localStorage.getItem("rebuild-password")||""),a=De().refresh,r=Object(n["ref"])(!1),s=function(){localStorage.setItem("rebuild-password",c.value),o.value=!1,r.value=!0,Ie(c.value).then((function(e){r.value=!1;var t=e.data;200===t.meta.code?(be["a"].success(t.meta.msg),a()):be["a"].error(t.meta.msg)}))},i=Object(n["ref"])(),d=function(){o.value=!0,setTimeout((function(){i.value.focus()}),50)};return{info:t,rebuild:s,showPassword:o,password:c,rebuilding:r,preRebuild:d,inputRef:i}}});o("08d5");Te.render=ke,Te.__scopeId="data-v-7fb59bb1";var Ue=Te;const Ee=Object(n["withScopeId"])("data-v-14b649c6");Object(n["pushScopeId"])("data-v-14b649c6");const Re={class:"header"};Object(n["popScopeId"])();const qe=Ee((e,t,o,c,a,r)=>{const s=Object(n["resolveComponent"])("a-spin"),i=Object(n["resolveComponent"])("router-link"),d=Object(n["resolveComponent"])("copy"),l=Object(n["resolveComponent"])("a-button"),u=Object(n["resolveComponent"])("download"),b=Object(n["resolveComponent"])("a-space"),p=Object(n["resolveComponent"])("a-divider");return Object(n["openBlock"])(),Object(n["createBlock"])(n["Fragment"],null,[Object(n["createVNode"])("div",Re,[Object(n["createVNode"])(i,{to:"/"},{default:Ee(()=>[e.info.logo?(Object(n["openBlock"])(),Object(n["createBlock"])("img",{key:0,src:e.info.logo,alt:"BaiYue云盘",style:{height:"56px",width:"auto"},id:"logo"},null,8,["src"])):(Object(n["openBlock"])(),Object(n["createBlock"])(s,{key:1}))]),_:1}),Object(n["createVNode"])(b,null,{default:Ee(()=>["file"===e.type?(Object(n["openBlock"])(),Object(n["createBlock"])(b,{key:0},{default:Ee(()=>[Object(n["createVNode"])(l,{type:"primary",shape:"circle",size:"large",onClick:e.copyFileLink},{icon:Ee(()=>[Object(n["createVNode"])(d)]),_:1},8,["onClick"]),Object(n["createVNode"])("a",{target:"_blank",href:e.downloadUrl},[Object(n["createVNode"])(l,{type:"primary",shape:"circle",size:"large"},{icon:Ee(()=>[Object(n["createVNode"])(u)]),_:1})],8,["href"])]),_:1})):Object(n["createCommentVNode"])("",!0)]),_:1})]),Object(n["createVNode"])(p,{class:"header-content"})],64)});var Ae=Object(n["defineComponent"])({name:"Header",setup:function(){var e=Object(ee["b"])(),t=Object(A["c"])(),o=Object(A["d"])(),c=Object(n["computed"])((function(){return e.state.info})),a=Object(n["ref"])(window.location.href),r=Object(n["computed"])((function(){return e.state.type})),s=me(),i=s.downloadUrl,d=s.copyFileLink,l=Object(n["ref"])(""),u=function(e){o.push(t.path+"?q="+e)};return{info:c,url:a,type:r,copyFileLink:d,downloadUrl:i,keyword:l,onSearch:u}}});o("17e6");Ae.render=qe,Ae.__scopeId="data-v-14b649c6";var He=Ae;const Ke={class:"not-found"},Ye=Object(n["createTextVNode"])(" 返回首页 ");function Je(e,t,o,c,a,r){const s=Object(n["resolveComponent"])("router-link"),i=Object(n["resolveComponent"])("a-button"),d=Object(n["resolveComponent"])("a-result");return Object(n["openBlock"])(),Object(n["createBlock"])("div",Ke,[Object(n["createVNode"])(d,{status:"404",title:"404","sub-title":"Sorry, the path you visited does not exist."},{extra:Object(n["withCtx"])(()=>[Object(n["createVNode"])(i,{type:"primary"},{default:Object(n["withCtx"])(()=>[Object(n["createVNode"])(s,{to:"/"},{default:Object(n["withCtx"])(()=>[Ye]),_:1})]),_:1})]),_:1})])}var We=Object(n["defineComponent"])({name:"NotFound"});We.render=Je;var Ge=We;const Xe=Object(n["withScopeId"])("data-v-17513f2b");Object(n["pushScopeId"])("data-v-17513f2b");const Qe={class:"path"},Ze={key:0};Object(n["popScopeId"])();const $e=Xe((e,t,o,c,a,r)=>{const s=Object(n["resolveComponent"])("home"),i=Object(n["resolveComponent"])("router-link"),d=Object(n["resolveComponent"])("a-breadcrumb");return Object(n["openBlock"])(),Object(n["createBlock"])("div",Qe,[Object(n["createVNode"])(s,{style:{"margin-right":"10px"}}),Object(n["createVNode"])(d,{routes:e.routes},{itemRender:Xe(({route:t,routes:o,paths:c})=>[e.q||o.indexOf(t)!==o.length-1?(Object(n["openBlock"])(),Object(n["createBlock"])(i,{key:1,to:"/"+c.join("/")},{default:Xe(()=>[Object(n["createTextVNode"])(Object(n["toDisplayString"])(t.breadcrumbName),1)]),_:2},1032,["to"])):(Object(n["openBlock"])(),Object(n["createBlock"])("span",Ze,Object(n["toDisplayString"])(t.breadcrumbName),1))]),_:1},8,["routes"])])});var et=Object(n["defineComponent"])({name:"Path",setup:function(){var e=Object(A["c"])(),t=Object(n["computed"])((function(){return e.query.q})),o=Object(n["computed"])((function(){var t=e.params.path;return t.map((function(e){return{path:e,breadcrumbName:e}}))}));return{routes:o,q:t}}});o("5013");et.render=$e,et.__scopeId="data-v-17513f2b";var tt=et;const ot=Object(n["withScopeId"])("data-v-7133190c");Object(n["pushScopeId"])("data-v-7133190c");const nt={class:"preview"},ct=Object(n["createTextVNode"])("下载"),at=Object(n["createTextVNode"])("复制直链"),rt={key:0,class:"doc-preview",id:"doc-preview"},st={key:2,class:"img-preview"},it={key:3,class:"text-preview"},dt={class:"video-preview",id:"video-preview"},lt={class:"audio-preview",id:"audio-preview"};Object(n["popScopeId"])();const ut=ot((e,t,o,c,a,r)=>{const s=Object(n["resolveComponent"])("a-button"),i=Object(n["resolveComponent"])("a-result"),d=Object(n["resolveComponent"])("v-md-preview"),l=Object(n["resolveComponent"])("a-spin");return Object(n["openBlock"])(),Object(n["createBlock"])("div",nt,[e.previewShow.other?(Object(n["openBlock"])(),Object(n["createBlock"])(i,{key:0,title:e.file.name},{icon:ot(()=>[(Object(n["openBlock"])(),Object(n["createBlock"])(Object(n["resolveDynamicComponent"])(e.file.icon),{class:"file-icon"}))]),extra:ot(()=>[Object(n["createVNode"])("a",{target:"_blank",href:e.downloadUrl},[Object(n["createVNode"])(s,{type:"primary"},{default:ot(()=>[ct]),_:1})],8,["href"]),Object(n["createVNode"])(s,{type:"primary",onClick:e.copyFileLink},{default:ot(()=>[at]),_:1},8,["onClick"])]),_:1},8,["title"])):Object(n["createCommentVNode"])("",!0),e.previewShow.spinning?(Object(n["openBlock"])(),Object(n["createBlock"])(l,{key:1,spinning:e.previewSpinning},{default:ot(()=>[e.previewShow.doc?(Object(n["openBlock"])(),Object(n["createBlock"])("div",rt)):Object(n["createCommentVNode"])("",!0),e.previewShow.iframe?(Object(n["openBlock"])(),Object(n["createBlock"])("iframe",{key:1,src:e.downloadUrl,id:"iframe-preview",ref:"iframe-preview",allowfullscreen:"allowfullscreen",webkitallowfullscreen:"true",mozallowfullscreen:"true",class:"iframe-preview",frameborder:"no",onLoad:t[1]||(t[1]=t=>e.previewSpinning=!1)},null,40,["src"])):Object(n["createCommentVNode"])("",!0),e.previewShow.image?(Object(n["openBlock"])(),Object(n["createBlock"])("div",st,[Object(n["createVNode"])("img",{onLoad:t[2]||(t[2]=t=>e.previewSpinning=!1),src:e.downloadUrl},null,40,["src"])])):Object(n["createCommentVNode"])("",!0),e.previewShow.text?(Object(n["openBlock"])(),Object(n["createBlock"])("div",it,[Object(n["createVNode"])(d,{text:e.text},null,8,["text"])])):Object(n["createCommentVNode"])("",!0)]),_:1},8,["spinning"])):Object(n["createCommentVNode"])("",!0),Object(n["withDirectives"])(Object(n["createVNode"])("div",dt,null,512),[[n["vShow"],e.previewShow.video]]),Object(n["withDirectives"])(Object(n["createVNode"])("div",lt,null,512),[[n["vShow"],e.previewShow.audio]])])});var bt=o("9ab4"),pt=o("f7a5"),ft=o.n(pt),jt=(o("764d"),o("9f61")),mt=o.n(jt),vt=Object(n["defineComponent"])({name:"Preview",setup:function(){var e,t,o=this,c=Object(ee["b"])(),a=Object(A["c"])(),r=Object(n["computed"])((function(){var e=c.state.data;return e.icon=le(e),e})),s=me(),i=s.downloadUrl,d=s.copyFileLink,l=Object(n["computed"])((function(){return c.state.info})),u=Object(n["ref"])(!0),b=Object(n["ref"])({image:!1,video:!1,audio:!1,doc:!1,other:!1,text:!1,iframe:!1,spinning:!1}),p=Object(n["computed"])((function(){return c.state.audios})),f=Object(n["ref"])(""),j=function(e){b.value.spinning=!0,u.value=!0,b.value.doc=!0,Pe(e.file_id).then((function(e){var t=e.data;if(200===t.meta.code){var o=aliyun.config({mount:document.querySelector("#doc-preview"),url:t.data.preview_url});o.setToken({token:t.data.access_token}),setTimeout((function(){u.value=!1}),200)}else be["a"].error(t.meta.msg)}))},m=function(n){return Object(bt["a"])(o,void 0,void 0,(function(){var o,r,s,d,m,v;return Object(bt["b"])(this,(function(O){switch(O.label){case 0:return[4,Se(decodeURI(a.path.substring(1)),c.state.password)];case 1:return o=O.sent().data,se.includes(n.file_extension.toLowerCase())?(j(n),[2]):"image"==n.category?(b.value.spinning=!0,u.value=!0,b.value.image=!0,[2]):"video"===n.category?(b.value.video=!0,r=n.file_extension,s="auto","flv"===r&&(s="flv"),d={container:document.getElementById("video-preview"),video:{url:o.data.url,type:s},pluginOptions:{flv:{config:{referrerPolicy:"no-referrer"}}},autoplay:!!l.value.autoplay,screenshot:!0},console.log(d),e=new ft.a(d),[2]):"audio"===n.category?(b.value.audio=!0,m={container:document.getElementById("audio-preview"),autoplay:!0,audio:Object(bt["c"])([{name:n.name,url:i.value,cover:l.value.music_img}],p.value),listMaxHeight:"65vh"},t=new mt.a(m),[2]):(null===(v=l.value.preview)||void 0===v?void 0:v.text.includes(n.file_extension.toLowerCase()))?(b.value.text=!0,u.value=!0,b.value.spinning=!0,Se(n.dir+n.name,c.state.password).then((function(e){var t=e.data;200===t.meta.code?Le(t.data.url).then((function(e){"md"===n.file_extension.toLowerCase()?f.value=e.data:f.value="```"+n.file_extension.toLowerCase()+"\n"+e.data+"\n```",u.value=!1})):be["a"].error(t.meta.msg)})),[2]):(b.value.other=!0,[2])}}))}))};return Object(n["onMounted"])((function(){m(r.value)})),Object(n["onBeforeUnmount"])((function(){t&&t.destroy(),e&&e.destroy()})),{file:r,previewSpinning:u,previewShow:b,downloadUrl:i,copyFileLink:d,text:f}}});o("d1ea");vt.render=ut,vt.__scopeId="data-v-7133190c";var Ot=vt;const ht=Object(n["withScopeId"])("data-v-089de3c1");Object(n["pushScopeId"])("data-v-089de3c1");const gt={class:"readme"};Object(n["popScopeId"])();const wt=ht((e,t,o,c,a,r)=>{const s=Object(n["resolveComponent"])("v-md-preview"),i=Object(n["resolveComponent"])("a-card"),d=Object(n["resolveComponent"])("a-spin");return Object(n["withDirectives"])((Object(n["openBlock"])(),Object(n["createBlock"])("div",gt,[Object(n["createVNode"])(d,{spinning:e.readmeSpinning},{default:ht(()=>[Object(n["createVNode"])(i,{title:"Readme.md",style:{width:"100%"},size:"small"},{default:ht(()=>[Object(n["createVNode"])(s,{text:e.readmeValue},null,8,["text"])]),_:1})]),_:1},8,["spinning"])],512)),[[n["vShow"],void 0!==e.readme]])});var yt=Object(n["defineComponent"])({name:"Readme",setup:function(){var e=Object(ee["b"])(),t=Object(n["computed"])((function(){return e.state.type})),o=Object(n["ref"])(!0),c=Object(n["ref"])(""),a=function(t){void 0!==t&&Se(t.dir+t.name,e.state.password).then((function(e){var t=e.data;200===t.meta.code&&Le(t.data.url).then((function(e){c.value=e.data,o.value=!1}))}))},r=Object(n["computed"])((function(){var t=e.state.data;if(!t.type){var o=e.state.data,n=o.find((function(e){return"readme.md"===e.name.toLowerCase()}));return a(n),n}}));return{type:t,readme:r,readmeValue:c,readmeSpinning:o}}});yt.render=wt,yt.__scopeId="data-v-089de3c1";var kt=yt,Ct=Object(n["defineComponent"])({name:"Home",components:{Header:He,Footer:Ue,Path:tt,Files:Oe,Preview:Ot,NotFound:Ge,Readme:kt},setup:function(){var e=Object(A["c"])(),t=Object(A["d"])(),o=Object(ee["b"])();o.dispatch("fetchInfo");var c=!1;navigator.userAgent.match(/MicroMessenger/i)&&navigator.userAgent.match(/android/i)&&(c=!0);var a=Object(n["computed"])((function(){return o.state.type})),r=De().refresh;Object(n["watch"])((function(){return e.fullPath}),(function(){r()})),Object(n["onMounted"])((function(){r()}));var s=Object(n["computed"])((function(){return 401===o.state.meta.code})),i=Object(n["ref"])();Object(n["watch"])(s,(function(){setTimeout((function(){s.value&&i.value&&i.value.focus()}),50)}));var d=Object(n["ref"])(o.state.password),l=function(){o.commit("setPassword",d.value),r()},u=function(){t.go(-1)};return{isAdrWx:c,type:a,showPassword:s,password:d,okPassword:l,cancelPassword:u,inputRef:i}}});o("f5b7");Ct.render=W,Ct.__scopeId="data-v-62fb27c4";var xt=Ct,Nt=[{path:"/",name:"Home",redirect:"/root"},{path:"/about",name:"About",component:function(){return o.e("about").then(o.bind(null,"f820"))}},{path:"/:path(.*)*",component:xt}],_t=Object(A["a"])({history:Object(A["b"])("/"),routes:Nt}),St=_t,Bt=o("d904"),Vt=o("56cd"),zt=function(e,t){void 0===e&&(e=""),void 0===t&&(t="");for(var o=e.split("."),n=t.split("."),c=Math.max(o.length,n.length),a=0,r=0;rr?o[r]:"0",i=isNaN(Number(s))?s.charCodeAt(0):Number(s),d=n.length>r?n[r]:"0",l=isNaN(Number(d))?d.charCodeAt(0):Number(d);if(il){a=1;break}}return a},It=function(){Fe().then((function(e){var t=e.data.tag_name.substring(1),o=ae.substring(1);1==zt(t,o)?Vt["a"].open({message:"发现新版本",description:"前端新版本:"+e.data.tag_name+", 请至"+e.data.html_url+"获取新版本",icon:Object(n["h"])(Bt["a"],{style:"color: #1890ff"})}):console.log(ae)}))},Pt=It,Ft=function(e){return new Promise((function(t,o){var n=document.createElement("script");n.type="text/javascript",n.onload=function(){t()},n.onerror=function(){o()},/^(http|https):\/\/([\w.]+\/?)\S*/.test(e)?n.src=e:n.text=e,document.querySelector("body").appendChild(n)}))},Lt=Ft,Mt=Object(ee["a"])({state:{info:{},loading:!0,password:localStorage.getItem("password")||"",meta:{code:200},data:[],type:"folder",audios:[]},mutations:{setLoading:function(e,t){e.loading=t},setPassword:function(e,t){e.password=t,localStorage.setItem("password",t)},setInfo:function(e,t){e.info=t},setMeta:function(e,t){e.meta=t},setData:function(e,t){if(!t)return e.type="no",void(e.data=[]);if(t.type)e.type="file";else{e.type="folder";for(var o=[],n=t,c=0,a=n;c log.log 2>&1 & 4 | 5 | echo "服务已启动,如果访问3000端口无响应,请在宝塔面板放行3000端口" -------------------------------------------------------------------------------- /vue/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /vue/.env.development: -------------------------------------------------------------------------------- 1 | NODE_ENV = 'development' 2 | 3 | VUE_APP_API_URL = 'http://localhost:3000/' -------------------------------------------------------------------------------- /vue/.env.production: -------------------------------------------------------------------------------- 1 | NODE_ENV = 'production' 2 | 3 | VUE_APP_API_URL = '/' -------------------------------------------------------------------------------- /vue/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/typescript/recommended' 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020 13 | }, 14 | rules: { 15 | 'camelcase': [1, {"properties": "never"}], 16 | "@typescript-eslint/no-namespace": "off", 17 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 18 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /vue/README.md: -------------------------------------------------------------------------------- 1 | # alist-web 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alist-web", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@ant-design/icons-vue": "^6.0.1", 12 | "@kangc/v-md-editor": "^2.2.2", 13 | "@types/dplayer": "^1.25.1", 14 | "ant-design-vue": "^2.0.1", 15 | "aplayer": "^1.10.1", 16 | "axios": "^0.21.1", 17 | "dplayer": "^1.26.0", 18 | "ts-md5": "^1.2.7", 19 | "vue": "^3.0.0", 20 | "vue-router": "^4.0.0-0", 21 | "vuex": "^4.0.0-0" 22 | }, 23 | "devDependencies": { 24 | "@typescript-eslint/eslint-plugin": "^2.33.0", 25 | "@typescript-eslint/parser": "^2.33.0", 26 | "@vue/cli-plugin-eslint": "~4.5.0", 27 | "@vue/cli-plugin-router": "~4.5.0", 28 | "@vue/cli-plugin-typescript": "~4.5.0", 29 | "@vue/cli-plugin-vuex": "~4.5.0", 30 | "@vue/cli-service": "~4.5.0", 31 | "@vue/compiler-sfc": "^3.0.0", 32 | "@vue/eslint-config-typescript": "^5.0.2", 33 | "eslint": "^6.7.2", 34 | "eslint-plugin-vue": "^7.0.0-0", 35 | "typescript": "~3.9.3" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baiyuetribe/alist_fiber/270ea9f1013ff6be0d104095bf5776a17a336ac1/vue/public/favicon.ico -------------------------------------------------------------------------------- /vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | <%= htmlWebpackPlugin.options.title %> 13 | 14 | 15 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /vue/src/assets/alist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baiyuetribe/alist_fiber/270ea9f1013ff6be0d104095bf5776a17a336ac1/vue/src/assets/alist.png -------------------------------------------------------------------------------- /vue/src/assets/global.css: -------------------------------------------------------------------------------- 1 | html,body,#app{ 2 | /* height: 100vh; */ 3 | width: 100%; 4 | margin: 0; 5 | padding: 0; 6 | /* overflow: hidden; */ 7 | } 8 | 9 | .ant-input-search,.ant-input-search input { 10 | background-color: transparent; 11 | } 12 | 13 | .ant-table-row{ 14 | cursor: pointer; 15 | } 16 | 17 | .ant-table td { 18 | white-space: nowrap; 19 | } 20 | 21 | .ant-table-body::-webkit-scrollbar { 22 | width: 0 !important 23 | } 24 | 25 | .ant-table-body{ 26 | overflow-x: overlay !important; 27 | overflow: -moz-scrollbars-none !important; 28 | -ms-overflow-style: none !important; 29 | } 30 | -------------------------------------------------------------------------------- /vue/src/components/Files.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 107 | 108 | -------------------------------------------------------------------------------- /vue/src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 62 | 63 | 86 | -------------------------------------------------------------------------------- /vue/src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 70 | 71 | -------------------------------------------------------------------------------- /vue/src/components/NotFound.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /vue/src/components/Path.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 42 | 43 | 53 | -------------------------------------------------------------------------------- /vue/src/components/Preview.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 234 | 235 | 264 | -------------------------------------------------------------------------------- /vue/src/components/Readme.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 56 | 57 | 60 | -------------------------------------------------------------------------------- /vue/src/hooks/useDownloadUrl.ts: -------------------------------------------------------------------------------- 1 | import { FileProps, GlobalDataProps } from "@/store"; 2 | import { backendUrl } from "@/utils/const"; 3 | import { copyToClip } from "@/utils/copy_clip"; 4 | import { message } from "ant-design-vue"; 5 | import { computed } from "vue"; 6 | import { useRoute } from "vue-router"; 7 | import { useStore } from "vuex"; 8 | import { Md5 } from 'ts-md5/dist/md5' 9 | 10 | function useDownloadUrl() { 11 | const store = useStore() 12 | const route = useRoute() 13 | const downloadUrl = computed(() => { 14 | let url = backendUrl + "d" + decodeURI(route.path) 15 | if(store.state.password){ 16 | const md5 = Md5.hashStr(store.state.password) as string 17 | url += '?pw=' + md5.substring(8, 24) 18 | } 19 | return url 20 | }) 21 | const copyFileLink = () => { 22 | copyToClip(downloadUrl.value) 23 | message.success("链接已复制到剪贴板.") 24 | } 25 | return { 26 | downloadUrl, 27 | copyFileLink 28 | } 29 | } 30 | 31 | export const useDownloadFile = () =>{ 32 | const store = useStore() 33 | const getFileDownLink = (file: FileProps)=>{ 34 | let url = backendUrl + 'd/' + file.dir + file.name 35 | if(store.state.password){ 36 | const md5 = Md5.hashStr(store.state.password) as string 37 | url += '?pw=' + md5.substring(8, 24) 38 | } 39 | return url 40 | } 41 | const copyFileLink = (file: FileProps) => { 42 | copyToClip(getFileDownLink(file)) 43 | message.success("链接已复制到剪贴板.") 44 | } 45 | return { 46 | getFileDownLink, 47 | copyFileLink, 48 | } 49 | } 50 | 51 | export default useDownloadUrl -------------------------------------------------------------------------------- /vue/src/hooks/usePassword.ts: -------------------------------------------------------------------------------- 1 | function usePassword() { 2 | 3 | } 4 | 5 | export default usePassword -------------------------------------------------------------------------------- /vue/src/hooks/useRefresh.ts: -------------------------------------------------------------------------------- 1 | import { GlobalDataProps } from "@/store" 2 | import { useRoute } from "vue-router" 3 | import { useStore } from "vuex" 4 | 5 | function useRefresh() { 6 | const store = useStore() 7 | const route = useRoute() 8 | const refresh = () => { 9 | store.dispatch('fetchPathOrSearch',{path: decodeURI(route.path.substring(1)), query: route.query['q']}) 10 | } 11 | return { 12 | refresh 13 | } 14 | } 15 | 16 | export default useRefresh -------------------------------------------------------------------------------- /vue/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { 3 | Button, Divider, Tag, Card, Breadcrumb, Table, Modal, Input, Result, Spin, Popover, Space, 4 | } from 'ant-design-vue' 5 | import { 6 | QrcodeOutlined, HomeOutlined, WindowsFilled, 7 | FileExcelFilled, FileMarkdownFilled, FilePdfFilled, 8 | FilePptFilled, FileWordFilled, FileZipFilled, 9 | AndroidFilled, AppleFilled, FileImageFilled, 10 | FileTextFilled, YoutubeFilled, CustomerServiceFilled, 11 | FileFilled, FolderFilled, CopyOutlined, DownloadOutlined 12 | } from '@ant-design/icons-vue' 13 | import 'ant-design-vue/dist/antd.css' 14 | import VMdPreview from '@kangc/v-md-editor/lib/preview'; 15 | import '@kangc/v-md-editor/lib/style/preview.css'; 16 | import githubTheme from '@kangc/v-md-editor/lib/theme/github.js'; 17 | import '@kangc/v-md-editor/lib/theme/style/github.css'; 18 | import './assets/global.css' 19 | import App from './App.vue' 20 | import router from './router' 21 | import store from './store' 22 | 23 | const app = createApp(App) 24 | 25 | VMdPreview.use(githubTheme) 26 | app.use(VMdPreview) 27 | 28 | app.use(Button) 29 | app.use(Divider) 30 | app.use(Tag) 31 | app.use(Card) 32 | app.use(Breadcrumb) 33 | app.use(Table) 34 | app.use(Modal) 35 | app.use(Input) 36 | app.use(Result) 37 | app.use(Spin) 38 | app.use(Popover) 39 | app.use(Space) 40 | app.component('qr-code', QrcodeOutlined) 41 | app.component('home', HomeOutlined) 42 | app.component('windows', WindowsFilled) 43 | app.component('file-excel', FileExcelFilled) 44 | app.component('file-markdown', FileMarkdownFilled) 45 | app.component('file-pdf', FilePdfFilled) 46 | app.component('file-ppt', FilePptFilled) 47 | app.component('file-word', FileWordFilled) 48 | app.component('file-zip', FileZipFilled) 49 | app.component('android', AndroidFilled) 50 | app.component('apple', AppleFilled) 51 | app.component('file-image', FileImageFilled) 52 | app.component('file-text', FileTextFilled) 53 | app.component('youtube', YoutubeFilled) 54 | app.component('customer-service', CustomerServiceFilled) 55 | app.component('file', FileFilled) 56 | app.component('folder', FolderFilled) 57 | app.component('copy', CopyOutlined) 58 | app.component('download', DownloadOutlined) 59 | 60 | app.use(store).use(router) 61 | app.mount('#app') 62 | -------------------------------------------------------------------------------- /vue/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' 2 | import Home from '../views/Home.vue' 3 | 4 | const routes: Array = [ 5 | { 6 | path: '/', 7 | name: 'Home', 8 | redirect: '/root' 9 | }, 10 | { 11 | path: '/about', 12 | name: 'About', 13 | // route level code-splitting 14 | // this generates a separate chunk (about.[hash].js) for this route 15 | // which is lazy-loaded when the route is visited. 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 17 | }, 18 | { 19 | path: '/:path(.*)*', 20 | component: Home 21 | } 22 | ] 23 | 24 | const router = createRouter({ 25 | history: createWebHistory(process.env.BASE_URL), 26 | routes 27 | }) 28 | 29 | export default router 30 | -------------------------------------------------------------------------------- /vue/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue' 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /vue/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import checkWebUpdate from '@/utils/check_update' 2 | import { backendUrl } from '@/utils/const' 3 | import loadJS from '@/utils/load_js' 4 | import { message } from 'ant-design-vue' 5 | import { createStore } from 'vuex' 6 | import { infoGet, pathPost, searchPost, rebuildGet } from '../utils/api' 7 | 8 | interface MetaProps { 9 | code: number; 10 | msg?: string; 11 | } 12 | 13 | interface RespProps

{ 14 | meta: MetaProps; 15 | data: P; 16 | } 17 | 18 | export interface ListProps

{ 19 | [index: number]: P; 20 | } 21 | 22 | interface InfoProps { 23 | title?: string; 24 | logo?: string; 25 | footer_text?: string; 26 | footer_url?: string; 27 | music_img?: string; 28 | check_update?: string; 29 | script?: string; 30 | autoplay?: boolean; 31 | preview?: { 32 | url: string; 33 | pre_process: string[]; 34 | extensions: string[]; 35 | text: string[]; 36 | max_size: number; 37 | }; 38 | } 39 | 40 | export interface FileProps { 41 | dir: string; 42 | file_extension: string; 43 | file_id: string; 44 | name: string; 45 | type: string; 46 | updated_at: string; 47 | category: string; 48 | content_type: string; 49 | size: number; 50 | password: ""; 51 | sizeStr: string; 52 | time: string; 53 | icon: string; 54 | } 55 | 56 | interface Audio { 57 | name: string; 58 | url: string; 59 | cover: string; 60 | } 61 | 62 | export interface GlobalDataProps { 63 | loading: boolean; 64 | info: InfoProps; 65 | password: string; 66 | meta: MetaProps; 67 | data: FileProps|FileProps[]; 68 | type: string; 69 | audios: Audio[]; 70 | } 71 | 72 | export default createStore({ 73 | state: { 74 | info: {}, 75 | loading: true, 76 | password: localStorage.getItem('password')||'', 77 | meta: { 78 | code: 200, 79 | }, 80 | data: [], 81 | type: 'folder', 82 | audios: [], 83 | }, 84 | mutations: { 85 | setLoading(state, loading) { 86 | state.loading = loading 87 | }, 88 | setPassword(state, password) { 89 | state.password = password 90 | localStorage.setItem('password', password) 91 | }, 92 | setInfo(state, info) { 93 | state.info = info 94 | }, 95 | setMeta(state, meta) { 96 | state.meta = meta 97 | }, 98 | setData(state, data) { 99 | if(!data) { 100 | state.type = 'no' 101 | state.data = [] 102 | return 103 | } 104 | if(data.type){ 105 | state.type = 'file' 106 | }else{ 107 | state.type = 'folder' 108 | const audios: Audio[] = [] 109 | const files = data as FileProps[] 110 | for(const file of files){ 111 | if(file.category === 'audio'){ 112 | audios.push({ 113 | name: file.name, 114 | url: backendUrl+'d/'+file.dir+file.name, 115 | cover: state.info.music_img||'https://img.oez.cc/2020/12/19/0f8b57866bdb5.gif' 116 | }) 117 | } 118 | } 119 | state.audios = audios 120 | } 121 | state.data = data 122 | } 123 | }, 124 | actions: { 125 | async fetchInfo({state, commit}) { 126 | const {data} = await infoGet() 127 | const infoData: InfoProps = data.data 128 | document.title = infoData.title||'Alist' 129 | if(infoData.check_update){ 130 | checkWebUpdate() 131 | } 132 | if(infoData.script){ 133 | loadJS(infoData.script) 134 | } 135 | if(!infoData.logo){ 136 | infoData.logo = require('../assets/alist.png') 137 | } 138 | commit('setInfo',infoData) 139 | }, 140 | async fetchPathOrSearch({state, commit}, {path, query}){ 141 | commit('setLoading', true) 142 | if(query){ 143 | const {data} = await searchPost(query, path) 144 | const {meta} =data 145 | if(meta.code !== 200){ 146 | message.error(meta.msg) 147 | } 148 | commit('setData',data.data) 149 | }else{ 150 | const {data} = await pathPost(path, state.password) 151 | const {meta} =data 152 | commit('setMeta', meta) 153 | if(meta.code !== 200){ 154 | message.error(meta.msg) 155 | } 156 | if(meta.code === 401){ 157 | return 158 | } 159 | commit('setData',data.data) 160 | } 161 | commit('setLoading', false) 162 | } 163 | }, 164 | getters: { 165 | }, 166 | modules: { 167 | } 168 | }) 169 | -------------------------------------------------------------------------------- /vue/src/utils/api.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import request from './request' 3 | 4 | export const getPost = (path: string, password: string) => { 5 | return request({ 6 | url: "get", 7 | method: "post", 8 | data: { 9 | path: path, 10 | password: password 11 | } 12 | }) 13 | } 14 | 15 | export const pathPost = (path: string, password: string) => { 16 | return request({ 17 | url: "path", 18 | method: "post", 19 | data: { 20 | path: path, 21 | password: password 22 | } 23 | }) 24 | } 25 | 26 | export const searchPost = (keyword: string, dir: string) => { 27 | return request({ 28 | url: "local_search", 29 | method: "post", 30 | data: { 31 | keyword: keyword, 32 | dir: dir 33 | } 34 | }) 35 | } 36 | 37 | export const infoGet = () => { 38 | return request({ 39 | url: "info", 40 | method: "get", 41 | }) 42 | } 43 | 44 | export const rebuildGet = (password: string) => { 45 | return request({ 46 | url: "rebuild/" + password, 47 | method: "get", 48 | }) 49 | } 50 | 51 | export const officePreviewPost = (fileId: string) => { 52 | return request({ 53 | url: "office_preview", 54 | method: "post", 55 | data: { 56 | 'file_id': fileId 57 | } 58 | }) 59 | } 60 | 61 | export const getWebLatest = () => { 62 | return axios.get('https://api.github.com/repos/Xhofe/alist-web/releases/latest') 63 | } 64 | 65 | export const getBackLatest = () => { 66 | return axios.get('https://api.github.com/repos/Xhofe/alist/releases/latest') 67 | } 68 | 69 | export const getText = (url: string) => { 70 | return axios.get(url) 71 | } -------------------------------------------------------------------------------- /vue/src/utils/base64.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Base64 encode / decode 4 | * http://www.webtoolkit.info/ 5 | * 6 | **/ 7 | 8 | export const Base64 = { 9 | // private property 10 | _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 11 | 12 | // public method for encoding 13 | encode: function (input: string) { 14 | let output = ""; 15 | let chr1, chr2, chr3, enc1, enc2, enc3, enc4; 16 | let i = 0; 17 | input = Base64._utf8_encode(input); 18 | while (i < input.length) { 19 | chr1 = input.charCodeAt(i++); 20 | chr2 = input.charCodeAt(i++); 21 | chr3 = input.charCodeAt(i++); 22 | enc1 = chr1 >> 2; 23 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 24 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 25 | enc4 = chr3 & 63; 26 | if (isNaN(chr2)) { 27 | enc3 = enc4 = 64; 28 | } else if (isNaN(chr3)) { 29 | enc4 = 64; 30 | } 31 | output = output + 32 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + 33 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); 34 | } 35 | return output; 36 | }, 37 | 38 | // public method for decoding 39 | decode: function (input: string) { 40 | let output = ""; 41 | let chr1, chr2, chr3; 42 | let enc1, enc2, enc3, enc4; 43 | let i = 0; 44 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 45 | while (i < input.length) { 46 | enc1 = this._keyStr.indexOf(input.charAt(i++)); 47 | enc2 = this._keyStr.indexOf(input.charAt(i++)); 48 | enc3 = this._keyStr.indexOf(input.charAt(i++)); 49 | enc4 = this._keyStr.indexOf(input.charAt(i++)); 50 | chr1 = (enc1 << 2) | (enc2 >> 4); 51 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 52 | chr3 = ((enc3 & 3) << 6) | enc4; 53 | output = output + String.fromCharCode(chr1); 54 | if (enc3 != 64) { 55 | output = output + String.fromCharCode(chr2); 56 | } 57 | if (enc4 != 64) { 58 | output = output + String.fromCharCode(chr3); 59 | } 60 | } 61 | output = Base64._utf8_decode(output); 62 | return output; 63 | }, 64 | 65 | // private method for UTF-8 encoding 66 | _utf8_encode: function (string: string) { 67 | string = string.replace(/\r\n/g, "\n"); 68 | let utftext = ""; 69 | for (let n = 0; n < string.length; n++) { 70 | let c = string.charCodeAt(n); 71 | if (c < 128) { 72 | utftext += String.fromCharCode(c); 73 | } 74 | else if ((c > 127) && (c < 2048)) { 75 | utftext += String.fromCharCode((c >> 6) | 192); 76 | utftext += String.fromCharCode((c & 63) | 128); 77 | } 78 | else { 79 | utftext += String.fromCharCode((c >> 12) | 224); 80 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 81 | utftext += String.fromCharCode((c & 63) | 128); 82 | } 83 | } 84 | return utftext; 85 | }, 86 | 87 | // private method for UTF-8 decoding 88 | _utf8_decode: function (utftext: string) { 89 | let string = ""; 90 | let i = 0 91 | let c = 0 92 | let c1 = 0 93 | let c2 = 0 94 | while (i < utftext.length) { 95 | c = utftext.charCodeAt(i); 96 | if (c < 128) { 97 | string += String.fromCharCode(c); 98 | i++; 99 | } 100 | else if ((c > 191) && (c < 224)) { 101 | c2 = utftext.charCodeAt(i + 1); 102 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 103 | i += 2 104 | } 105 | else { 106 | c2 = utftext.charCodeAt(i + 1); 107 | c1 = utftext.charCodeAt(i + 2); 108 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c1 & 63)); 109 | i += 3; 110 | } 111 | } 112 | return string; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /vue/src/utils/check_update.ts: -------------------------------------------------------------------------------- 1 | import { SmileOutlined } from "@ant-design/icons-vue" 2 | import { notification } from "ant-design-vue" 3 | import { h } from "vue" 4 | import { getWebLatest } from "./api" 5 | import { VERSION } from "./const" 6 | import { versionStringCompare } from "./version_compare" 7 | 8 | const checkWebUpdate = () => { 9 | getWebLatest().then(res=>{ 10 | const lasted=res.data.tag_name.substring(1) 11 | const now=VERSION.substring(1) 12 | if(versionStringCompare(lasted,now)==1){ 13 | notification.open({ 14 | message: '发现新版本', 15 | description: 16 | '前端新版本:'+res.data.tag_name+', 请至'+res.data.html_url+'获取新版本', 17 | icon: h(SmileOutlined,{style: 'color: #1890ff'}), 18 | }); 19 | }else{ 20 | //已经是最新版本 21 | console.log(VERSION) 22 | } 23 | }) 24 | } 25 | 26 | export default checkWebUpdate -------------------------------------------------------------------------------- /vue/src/utils/const.ts: -------------------------------------------------------------------------------- 1 | import { getUrl } from "./get_url" 2 | 3 | export const VERSION = 'v1.0.0' 4 | 5 | export const fileExtensions: { [key: string]: string } = { 6 | exe: 'windows', 7 | xls: 'file-excel', 8 | xlsx: 'file-excel', 9 | md: 'file-markdown', 10 | pdf: 'file-pdf', 11 | ppt: 'file-ppt', 12 | pptx: 'file-ppt', 13 | doc: 'file-word', 14 | docx: 'file-word', 15 | // jpg:'file-jpg', 16 | zip: 'file-zip', 17 | gz: 'file-zip', 18 | rar: 'file-zip', 19 | "7z": 'file-zip', 20 | tar: 'file-zip', 21 | jar: 'file-zip', 22 | xz: 'file-zip', 23 | apk: 'android', 24 | dmg: 'apple', 25 | ipa: 'apple', 26 | } 27 | 28 | export const doc = ['pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'] 29 | 30 | export const categorys: { [key: string]: string } = { 31 | image: 'file-image', 32 | doc: 'file-text', 33 | video: 'youtube', 34 | audio: 'customer-service', 35 | } 36 | 37 | export const backendUrl: string = process.env.VUE_APP_API_URL != '/' ? process.env.VUE_APP_API_URL : getUrl('') 38 | -------------------------------------------------------------------------------- /vue/src/utils/copy_clip.ts: -------------------------------------------------------------------------------- 1 | export const copyToClip = (content: string) => { 2 | const aux = document.createElement("textarea"); 3 | // aux.setAttribute("value", content); 4 | aux.value = content 5 | document.body.appendChild(aux) 6 | aux.select() 7 | document.execCommand("copy") 8 | document.body.removeChild(aux) 9 | } -------------------------------------------------------------------------------- /vue/src/utils/date.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * full 3 | * 用于月日时分秒小于10补0 4 | * @param {*} p 5 | */ 6 | export const full = (p: number) => { 7 | return p < 10 ? '0' + p : p 8 | } 9 | 10 | /** 11 | * formateDate 12 | * 将timestamp日期格式化为 yyyy-mm-dd hh-mm-ss 13 | * @param {*} date 14 | */ 15 | export function formatDate(dateStr: string) { 16 | const date = new Date(dateStr) 17 | const year = date.getFullYear() 18 | const mon = date.getMonth() + 1 19 | const day = date.getDate() 20 | const hour = date.getHours() 21 | const min = date.getMinutes() 22 | const sec = date.getSeconds() 23 | 24 | return year + '-' + full(mon) + '-' + full(day) + ' ' + 25 | full(hour) + ':' + full(min) + ':' + full(sec) 26 | } 27 | -------------------------------------------------------------------------------- /vue/src/utils/file_size.ts: -------------------------------------------------------------------------------- 1 | export function getFileSize(size: number){ 2 | if (!size) 3 | return ""; 4 | 5 | const num = 1024.00; //byte 6 | 7 | if (size < num) 8 | return size + "B"; 9 | if (size < Math.pow(num, 2)) 10 | return (size / num).toFixed(2) + "K"; //kb 11 | if (size < Math.pow(num, 3)) 12 | return (size / Math.pow(num, 2)).toFixed(2) + "M"; //M 13 | if (size < Math.pow(num, 4)) 14 | return (size / Math.pow(num, 3)).toFixed(2) + "G"; //G 15 | return (size / Math.pow(num, 4)).toFixed(2) + "T"; //T 16 | } -------------------------------------------------------------------------------- /vue/src/utils/get_icon.ts: -------------------------------------------------------------------------------- 1 | import { FileProps } from "@/store" 2 | import { categorys, fileExtensions } from "./const" 3 | 4 | export const getIcon = (record: FileProps) => { 5 | if (record.type=='folder'){ 6 | return 'folder' 7 | } 8 | if (Object.prototype.hasOwnProperty.call(fileExtensions,record.file_extension)){ 9 | return fileExtensions[record.file_extension] 10 | } 11 | if (Object.prototype.hasOwnProperty.call(categorys,record.category)){ 12 | return categorys[record.category] 13 | } 14 | return 'file' 15 | } 16 | -------------------------------------------------------------------------------- /vue/src/utils/get_url.ts: -------------------------------------------------------------------------------- 1 | export const getUrl=(fullUrl: string)=>{ 2 | if(!fullUrl){ 3 | fullUrl=window.location.href 4 | } 5 | const urlArr=fullUrl.split('/') 6 | return urlArr.slice(0,3).join('/')+'/' 7 | } -------------------------------------------------------------------------------- /vue/src/utils/load_js.ts: -------------------------------------------------------------------------------- 1 | const loadJS = (content: string) => { 2 | return new Promise((resolve,reject)=>{ 3 | const script = document.createElement('script') 4 | script.type = "text/javascript" 5 | script.onload = ()=>{ 6 | resolve() 7 | } 8 | script.onerror = ()=>{ 9 | reject() 10 | } 11 | if(/^(http|https):\/\/([\w.]+\/?)\S*/.test(content)){ 12 | script.src=content 13 | }else{ 14 | script.text= content 15 | } 16 | document.querySelector('body')!.appendChild(script) 17 | }) 18 | } 19 | 20 | export default loadJS -------------------------------------------------------------------------------- /vue/src/utils/request.ts: -------------------------------------------------------------------------------- 1 | import { message } from 'ant-design-vue' 2 | import axios from 'axios' 3 | 4 | const instance = axios.create({ 5 | baseURL: process.env.VUE_APP_API_URL+'api/', 6 | // timeout: 5000 7 | headers: { 8 | 'Content-Type': "application/json;charset=utf-8" 9 | }, 10 | withCredentials: false, 11 | }) 12 | 13 | instance.interceptors.request.use( 14 | config => { 15 | // do something before request is sent 16 | return config 17 | }, 18 | error => { 19 | // do something with request error 20 | console.log('Error: ' + error.message) // for debug 21 | return Promise.reject(error) 22 | } 23 | ) 24 | 25 | // response interceptor 26 | instance.interceptors.response.use( 27 | response => { 28 | // const res = response.data 29 | return response 30 | }, 31 | error => { 32 | // 响应失败 33 | console.log(error) // for debug 34 | if (!error.response||error.response.data.meta == undefined){ 35 | message.error('后端网络异常,请检查后端程序是否运行或检查网络连接!') 36 | return Promise.reject(error) 37 | } 38 | // return Promise.reject(error) 39 | return error.response.data 40 | } 41 | ) 42 | 43 | export default instance -------------------------------------------------------------------------------- /vue/src/utils/version_compare.ts: -------------------------------------------------------------------------------- 1 | export const versionStringCompare = (preVersion='', lastVersion='') => { 2 | const sources = preVersion.split('.'); 3 | const dests = lastVersion.split('.'); 4 | const maxL = Math.max(sources.length, dests.length); 5 | let result = 0; 6 | for (let i = 0; i < maxL; i++) { 7 | const preValue = sources.length>i ? sources[i]:'0'; 8 | const preNum = isNaN(Number(preValue)) ? preValue.charCodeAt(0) : Number(preValue); 9 | const lastValue = dests.length>i ? dests[i]:'0'; 10 | const lastNum = isNaN(Number(lastValue)) ? lastValue.charCodeAt(0) : Number(lastValue); 11 | if (preNum < lastNum) { 12 | result = -1; 13 | break; 14 | } else if (preNum > lastNum) { 15 | result = 1; 16 | break; 17 | } 18 | } 19 | return result; 20 | } -------------------------------------------------------------------------------- /vue/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /vue/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 96 | 97 | -------------------------------------------------------------------------------- /vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "target": "es5", 5 | "module": "esnext", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "importHelpers": true, 9 | "moduleResolution": "node", 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "sourceMap": true, 14 | "baseUrl": ".", 15 | "types": [ 16 | "webpack-env" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "esnext", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /vue/vue.config.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | publicPath: '/', 4 | outputDir: 'dist', 5 | //放置生成的静态资源 (js、css、img、fonts) 的目录 6 | assetsDir: 'static', 7 | //指定生成的 index.html 的输出路径 8 | indexPath: 'index.html', 9 | //去除map 10 | productionSourceMap:false, 11 | devServer: { 12 | port: 5277, 13 | // proxy: 'http://127.0.0.1:3000' 14 | // proxy: { 15 | // '/api': { 16 | // target: 'http://localhost:3000', 17 | // changeOrigin: true, 18 | // // pathRewrite:{ 19 | // // '^/api':'' 20 | // // } 21 | // } 22 | // } 23 | } 24 | } --------------------------------------------------------------------------------