├── .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 | 
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
12 |
13 |
14 | {{ text }}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
107 |
108 |
--------------------------------------------------------------------------------
/vue/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
62 |
63 |
86 |
--------------------------------------------------------------------------------
/vue/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
33 |
34 |
35 |
36 |
70 |
71 |
--------------------------------------------------------------------------------
/vue/src/components/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 返回首页
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
22 |
--------------------------------------------------------------------------------
/vue/src/components/Path.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ route.breadcrumbName }}
8 |
9 |
10 | {{ route.breadcrumbName }}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
42 |
43 |
53 |
--------------------------------------------------------------------------------
/vue/src/components/Preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 下载
11 |
12 | 复制直链
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
32 |
33 |
34 |
![]()
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
234 |
235 |
264 |
--------------------------------------------------------------------------------
/vue/src/components/Readme.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
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 |
2 |
3 |
4 |
5 |
一款阿里云盘的目录文件列表程序,后端基于go语言fiber框架重构原始项目,前端使用vue和ant design。
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/vue/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
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 | }
--------------------------------------------------------------------------------