mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-10-10 21:13:10 +08:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d19b49a8d | |||
| 4fa11879f2 | |||
| abe9d9237a | |||
| e4d206d59c | |||
| 8636014397 | |||
| c0f50ffeff | |||
| b677d6ad21 | |||
| 443067b80f | |||
| 3138e031f5 | |||
| d137ef8759 | |||
| 389226662c | |||
| 9cb548d4f7 | |||
| 0e7083a713 | |||
| 46f09836f3 | |||
| e146054679 | |||
| 3b2a729dc6 | |||
| d18a752732 | |||
| b9676182c9 | |||
| 434eb25408 | |||
| 858291876b | |||
| dcebf5257f | |||
| 0cd4624a36 | |||
| fcd9c59089 | |||
| b394711859 | |||
| 495c3f25e9 | |||
| d5e3527bfb | |||
| ba7c33a2bb | |||
| bf3f741b22 | |||
| 02e665ae37 | |||
| bacbf7bc1b | |||
| 4af469efed | |||
| 52cddc431a | |||
| 17f8c4ae1c | |||
| 070b6294cb | |||
| c05c6b9a50 | |||
| a7ce9451f3 | |||
| 430b4cf723 |
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
@@ -0,0 +1,71 @@
|
||||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ubuntu-latest]
|
||||
go-version: [1.15]
|
||||
name: Build
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install gcc-mingw-w64-x86-64
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross
|
||||
sudo apt-get -y install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
go get -v -t -d ./...
|
||||
if [ -f Gopkg.toml ]; then
|
||||
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
|
||||
dep ensure
|
||||
fi
|
||||
- name: Build linux
|
||||
run: |
|
||||
CC=gcc CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o alist_linux_amd64 alist.go
|
||||
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o alist_linux_arm64 alist.go
|
||||
CC=arm-linux-gnueabihf-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm go build -o alist_linux_arm alist.go
|
||||
|
||||
- name: Build windows
|
||||
run: |
|
||||
CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o alist_windows_amd64.exe alist.go
|
||||
|
||||
- name: Upload artifacts linux_amd64
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: alist_linux_amd64
|
||||
path: alist_linux_amd64
|
||||
|
||||
- name: Upload artifacts linux_arm64
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: alist_linux_arm64
|
||||
path: alist_linux_arm64
|
||||
|
||||
- name: Upload artifacts linux_arm
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: alist_linux_arm
|
||||
path: alist_linux_arm
|
||||
|
||||
- name: Upload artifacts windows_amd64
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: alist_windows_amd64
|
||||
path: alist_windows_amd64.exe
|
||||
@@ -0,0 +1,28 @@
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
-
|
||||
name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+4
-13
@@ -1,7 +1,7 @@
|
||||
.idea/
|
||||
.DS_Store
|
||||
output/
|
||||
/dist/
|
||||
dist/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
@@ -20,15 +20,6 @@ output/
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
/bin/*
|
||||
*.json
|
||||
/build
|
||||
/data/
|
||||
/tmp/
|
||||
/log/
|
||||
/lang/
|
||||
/daemon/
|
||||
/public/dist/*
|
||||
/!public/dist/README.md
|
||||
|
||||
.VSCodeCounter
|
||||
*.yml
|
||||
bin/*
|
||||
alist
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 微凉
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,64 @@
|
||||
<p align="center">
|
||||
<img src="https://img.oez.cc/2020/12/24/1fb16bc25a4f6.png" alt="AList Logo" width=200/>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="Release version"></a>
|
||||
<a href="https://github.com/Xhofe/alist/actions?query=workflow%3ABuild"><img src="https://img.shields.io/github/workflow/status/Xhofe/alist/build?style=flat-square" alt="Build status"></a>
|
||||
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/downloads/Xhofe/alist/total?style=flat-square" alt="Downloads"></a>
|
||||
<a href="https://github.com/Xhofe/alist/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Xhofe/alist?style=flat-square" alt="License"></a>
|
||||
<a href="https://pay.xhofe.top">
|
||||
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square" alt="donate">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
### 这是什么?
|
||||
|
||||
一款阿里云盘的目录文件列表程序,后端基于`golang`最好的`http`框架`gin`,前端使用`vue`和`ant design`。
|
||||
|
||||
### 前端项目地址
|
||||
|
||||
- https://github.com/Xhofe/alist-web
|
||||
|
||||
### 演示地址
|
||||
|
||||
- https://alist.nn.ci (稳定版本)
|
||||
- https://alist.now.sh (开发版本)
|
||||
- https://alist-plyr.now.sh (plyr分支版本)
|
||||
|
||||
### 预览
|
||||
|
||||
<a href="https://alist.nn.ci/"><img src="https://img.oez.cc/2020/12/24/d81d2dab3e5f0.png"></a>
|
||||
|
||||
### 支持的功能
|
||||
|
||||
- 自动刷新`token`,`refresh_token`自动更新,失效时间未知,本人使用过程中没有失效过。
|
||||
- 图片、视频、音频预览
|
||||
- 目录加密
|
||||
- `Readme`渲染
|
||||
- 自定义根目录
|
||||
- 文件直链下载
|
||||
- …
|
||||
|
||||
#### TODO
|
||||
|
||||
- [x] 排序
|
||||
- [x] 文件预览
|
||||
- [x] 图片
|
||||
- [x] 视频
|
||||
- [x] 音频
|
||||
- [x] `Readme`渲染
|
||||
- [x] 密码加密
|
||||
- [ ] 搜索与翻页
|
||||
- [x] 文件直链
|
||||
- [ ] 路径优化
|
||||
- [x] 缓存
|
||||
|
||||
### 如何使用
|
||||
|
||||
- https://www.nn.ci/archives/alist.html
|
||||
|
||||
### License
|
||||
|
||||
The `AList` is open-source software licensed under the MIT license.
|
||||
@@ -0,0 +1,78 @@
|
||||
package alidrive
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// use token login
|
||||
func TokenLogin() (*TokenLoginResp, error) {
|
||||
log.Infof("尝试使用token登录...")
|
||||
url := "https://auth.aliyundrive.com/v2/oauth/token_login"
|
||||
req := TokenLoginReq{Token: conf.Conf.AliDrive.LoginToken}
|
||||
log.Debugf("token_login_req:%+v", req)
|
||||
var tokenLogin TokenLoginResp
|
||||
if body, err := DoPost(url, req, false); err != nil {
|
||||
log.Errorf("tokenLogin-doPost出错:%s", err.Error())
|
||||
return nil, err
|
||||
} else {
|
||||
if err = json.Unmarshal(body, &tokenLogin); err != nil {
|
||||
log.Errorf("解析json[%s]出错:%s", string(body), err.Error())
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if tokenLogin.IsAvailable() {
|
||||
return &tokenLogin, nil
|
||||
}
|
||||
return nil, fmt.Errorf("登录token失效,请更换:%s", tokenLogin.Message)
|
||||
}
|
||||
|
||||
// get access token
|
||||
func GetToken(tokenLogin *TokenLoginResp) (*TokenResp, error) {
|
||||
log.Infof("获取API token...")
|
||||
url := "https://websv.aliyundrive.com/token/get"
|
||||
code := utils.GetCode(tokenLogin.Goto)
|
||||
if code == "" {
|
||||
return nil, fmt.Errorf("获取code出错")
|
||||
}
|
||||
req := GetTokenReq{Code: code}
|
||||
var token TokenResp
|
||||
if body, err := DoPost(url, req, false); err != nil {
|
||||
log.Errorf("tokenLogin-doPost出错:%s", err.Error())
|
||||
return nil, err
|
||||
} else {
|
||||
if err = json.Unmarshal(body, &token); err != nil {
|
||||
log.Errorf("解析json[%s]出错:%s", string(body), err.Error())
|
||||
log.Errorf("此处json解析失败应该是code失效")
|
||||
return nil, fmt.Errorf("code失效")
|
||||
}
|
||||
}
|
||||
return &token, nil
|
||||
}
|
||||
|
||||
// refresh access_token token by refresh_token
|
||||
func RefreshToken() bool {
|
||||
log.Infof("刷新token...")
|
||||
url := "https://websv.aliyundrive.com/token/refresh"
|
||||
req := RefreshTokenReq{RefreshToken: conf.Conf.AliDrive.RefreshToken}
|
||||
var token TokenResp
|
||||
if body, err := DoPost(url, req, false); err != nil {
|
||||
log.Errorf("tokenLogin-doPost出错:%s", err.Error())
|
||||
return false
|
||||
} else {
|
||||
if err = json.Unmarshal(body, &token); err != nil {
|
||||
log.Errorf("解析json[%s]出错:%s", string(body), err.Error())
|
||||
log.Errorf("此处json解析失败应该是refresh_token失效")
|
||||
return false
|
||||
}
|
||||
}
|
||||
//刷新成功 更新token并写入文件
|
||||
conf.Conf.AliDrive.AccessToken = token.AccessToken
|
||||
conf.Conf.AliDrive.RefreshToken = token.RefreshToken
|
||||
conf.Authorization = token.TokenType + "\t" + token.AccessToken
|
||||
utils.WriteToYml(conf.Con, conf.Conf)
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package alidrive
|
||||
|
||||
var (
|
||||
User *UserInfo
|
||||
)
|
||||
@@ -0,0 +1,67 @@
|
||||
package alidrive
|
||||
|
||||
// list request bean
|
||||
type ListReq struct {
|
||||
DriveId string `json:"drive_id"`
|
||||
Fields string `json:"fields"`
|
||||
ImageThumbnailProcess string `json:"image_thumbnail_process"`
|
||||
ImageUrlProcess string `json:"image_url_process"`
|
||||
Limit int `json:"limit"`
|
||||
Marker string `json:"marker"`
|
||||
OrderBy string `json:"order_by"`
|
||||
OrderDirection string `json:"order_direction"`
|
||||
ParentFileId string `json:"parent_file_id"`
|
||||
VideoThumbnailProcess string `json:"video_thumbnail_process"`
|
||||
}
|
||||
|
||||
// get request bean
|
||||
type GetReq struct {
|
||||
DriveId string `json:"drive_id"`
|
||||
FileId string `json:"file_id"`
|
||||
ImageThumbnailProcess string `json:"image_thumbnail_process"`
|
||||
VideoThumbnailProcess string `json:"video_thumbnail_process"`
|
||||
}
|
||||
|
||||
// download request bean
|
||||
type DownloadReq struct {
|
||||
DriveId string `json:"drive_id"`
|
||||
FileId string `json:"file_id"`
|
||||
ExpireSec int `json:"expire_sec"`
|
||||
FileName string `json:"file_name"`
|
||||
}
|
||||
|
||||
// search request bean
|
||||
type SearchReq struct {
|
||||
DriveId string `json:"drive_id"`
|
||||
ImageThumbnailProcess string `json:"image_thumbnail_process"`
|
||||
ImageUrlProcess string `json:"image_url_process"`
|
||||
Limit int `json:"limit"`
|
||||
Marker string `json:"marker"`
|
||||
OrderBy string `json:"order_by"` //"type ASC,updated_at DESC"
|
||||
|
||||
Query string `json:"query"` // "name match '测试文件'"
|
||||
|
||||
VideoThumbnailProcess string `json:"video_thumbnail_process"`
|
||||
}
|
||||
|
||||
// token_login request bean
|
||||
type TokenLoginReq struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// get_token request bean
|
||||
type GetTokenReq struct {
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
// refresh_token request bean
|
||||
type RefreshTokenReq struct {
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
// office_preview_url request bean
|
||||
type OfficePreviewUrlReq struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DriveId string `json:"drive_id"`
|
||||
FileId string `json:"file_id"`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,184 @@
|
||||
package alidrive
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// response bean methods
|
||||
type RespHandle interface {
|
||||
IsAvailable() bool // check available
|
||||
GetCode() string // get err code
|
||||
GetMessage() string // get err message
|
||||
SetCode(code string) // set err code
|
||||
}
|
||||
|
||||
// common response bean
|
||||
type RespError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (resp *RespError) IsAvailable() bool {
|
||||
return resp.Code == ""
|
||||
}
|
||||
|
||||
func (resp *RespError) GetCode() string {
|
||||
return resp.Code
|
||||
}
|
||||
|
||||
func (resp *RespError) GetMessage() string {
|
||||
return resp.Message
|
||||
}
|
||||
|
||||
func (resp *RespError) SetCode(code string) {
|
||||
resp.Code = code
|
||||
}
|
||||
|
||||
// user_info response bean
|
||||
type UserInfo struct {
|
||||
RespError
|
||||
DomainId string `json:"domain_id"`
|
||||
UserId string `json:"user_id"`
|
||||
Avatar string `json:"avatar"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
Email string `json:"email"`
|
||||
NickName string `json:"nick_name"`
|
||||
Phone string `json:"phone"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
UserName string `json:"user_name"`
|
||||
Description string `json:"description"`
|
||||
DefaultDriveId string `json:"default_drive_id"`
|
||||
UserData map[string]interface{} `json:"user_data"`
|
||||
}
|
||||
|
||||
// folder files response bean
|
||||
type Files struct {
|
||||
RespError
|
||||
Items []File `json:"items"`
|
||||
NextMarker string `json:"next_marker"`
|
||||
Readme string `json:"readme"` // Deprecated
|
||||
Paths []Path `json:"paths"`
|
||||
}
|
||||
|
||||
// path bean
|
||||
type Path struct {
|
||||
Name string `json:"name"`
|
||||
FileId string `json:"file_id"`
|
||||
}
|
||||
|
||||
// file response bean
|
||||
type File struct {
|
||||
RespError
|
||||
DriveId string `json:"drive_id"`
|
||||
CreatedAt *time.Time `json:"created_at"`
|
||||
DomainId string `json:"domain_id"`
|
||||
EncryptMode string `json:"encrypt_mode"`
|
||||
FileExtension string `json:"file_extension"`
|
||||
FileId string `json:"file_id"`
|
||||
Hidden bool `json:"hidden"`
|
||||
Name string `json:"name"`
|
||||
ParentFileId string `json:"parent_file_id"`
|
||||
Starred bool `json:"starred"`
|
||||
Status string `json:"status"`
|
||||
Type string `json:"type"`
|
||||
UpdatedAt *time.Time `json:"updated_at"`
|
||||
// 文件多出部分
|
||||
Category string `json:"category"`
|
||||
ContentHash string `json:"content_hash"`
|
||||
ContentHashName string `json:"content_hash_name"`
|
||||
ContentType string `json:"content_type"`
|
||||
Crc64Hash string `json:"crc_64_hash"`
|
||||
DownloadUrl string `json:"download_url"`
|
||||
PunishFlag int64 `json:"punish_flag"`
|
||||
Size int64 `json:"size"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
Url string `json:"url"`
|
||||
ImageMediaMetadata map[string]interface{} `json:"image_media_metadata"`
|
||||
|
||||
Paths []Path `json:"paths"`
|
||||
}
|
||||
|
||||
type DownloadResp struct {
|
||||
RespError
|
||||
Expiration string `json:"expiration"`
|
||||
Method string `json:"method"`
|
||||
Size int64 `json:"size"`
|
||||
Url string `json:"url"`
|
||||
//RateLimit struct{
|
||||
// PartSize int `json:"part_size"`
|
||||
// PartSpeed int `json:"part_speed"`
|
||||
//} `json:"rate_limit"`//rate limit
|
||||
}
|
||||
|
||||
// token_login response bean
|
||||
type TokenLoginResp struct {
|
||||
RespError
|
||||
Goto string `json:"goto"`
|
||||
}
|
||||
|
||||
// token response bean
|
||||
type TokenResp struct {
|
||||
RespError
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
|
||||
UserInfo
|
||||
|
||||
DefaultSboxDriveId string `json:"default_sbox_drive_id"`
|
||||
ExpireTime *time.Time `json:"expire_time"`
|
||||
State string `json:"state"`
|
||||
ExistLink []interface{} `json:"exist_link"`
|
||||
NeedLink bool `json:"need_link"`
|
||||
PinSetup bool `json:"pin_setup"`
|
||||
IsFirstLogin bool `json:"is_first_login"`
|
||||
NeedRpVerify bool `json:"need_rp_verify"`
|
||||
DeviceId string `json:"device_id"`
|
||||
}
|
||||
|
||||
// office_preview_url response bean
|
||||
type OfficePreviewUrlResp struct {
|
||||
RespError
|
||||
PreviewUrl string `json:"preview_url"`
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
|
||||
// check password
|
||||
func HasPassword(files *Files) string {
|
||||
fileList := files.Items
|
||||
for i, file := range fileList {
|
||||
if strings.HasPrefix(file.Name, ".password-") {
|
||||
files.Items = fileList[:i+copy(fileList[i:], fileList[i+1:])]
|
||||
return file.Name[10:]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Deprecated: check readme, implemented by the front end now
|
||||
func HasReadme(files *Files) string {
|
||||
fileList := files.Items
|
||||
for _, file := range fileList {
|
||||
if file.Name == "Readme.md" {
|
||||
resp, err := http.Get(file.Url)
|
||||
if err != nil {
|
||||
log.Errorf("Get Readme出错:%s", err.Error())
|
||||
return ""
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Errorf("读取 Readme出错:%s", err.Error())
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "github.com/Xhofe/alist/bootstrap"
|
||||
|
||||
// main function
|
||||
func main() {
|
||||
bootstrap.Run()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/alidrive"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// init aliyun drive
|
||||
func InitAliDrive() bool {
|
||||
log.Infof("初始化阿里云盘...")
|
||||
//首先token_login
|
||||
if conf.Conf.AliDrive.RefreshToken == "" {
|
||||
tokenLogin, err := alidrive.TokenLogin()
|
||||
if err != nil {
|
||||
log.Errorf("登录失败:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
//然后get_token
|
||||
token, err := alidrive.GetToken(tokenLogin)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
conf.Authorization = token.TokenType + "\t" + token.AccessToken
|
||||
} else {
|
||||
conf.Authorization = conf.Bearer + conf.Conf.AliDrive.AccessToken
|
||||
}
|
||||
log.Debugf("token:%s", conf.Authorization)
|
||||
user, err := alidrive.GetUserInfo()
|
||||
if err != nil {
|
||||
log.Errorf("初始化用户失败:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
log.Infof("当前用户信息:%+v", user)
|
||||
alidrive.User = user
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// init request client
|
||||
func InitClient() {
|
||||
log.Infof("初始化client...")
|
||||
conf.Client = &http.Client{}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
serv "github.com/Xhofe/alist/server"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&conf.Debug, "debug", false, "use debug mode")
|
||||
flag.BoolVar(&conf.Help, "help", false, "show usage help")
|
||||
flag.BoolVar(&conf.Version, "version", false, "show version info")
|
||||
flag.StringVar(&conf.Con, "conf", "conf.yml", "config file")
|
||||
flag.BoolVar(&conf.SkipUpdate, "skip-update", false, "skip update")
|
||||
}
|
||||
|
||||
// bootstrap run
|
||||
func Run() {
|
||||
flag.Parse()
|
||||
if conf.Help {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
if conf.Version {
|
||||
fmt.Println("Current version:" + conf.VERSION)
|
||||
return
|
||||
}
|
||||
start()
|
||||
}
|
||||
|
||||
// print asc
|
||||
func printASC() {
|
||||
log.Info(`
|
||||
________ ___ ___ ________ _________
|
||||
|\ __ \|\ \ |\ \|\ ____\|\___ ___\
|
||||
\ \ \|\ \ \ \ \ \ \ \ \___|\|___ \ \_|
|
||||
\ \ __ \ \ \ \ \ \ \_____ \ \ \ \
|
||||
\ \ \ \ \ \ \____\ \ \|____|\ \ \ \ \
|
||||
\ \__\ \__\ \_______\ \__\____\_\ \ \ \__\
|
||||
\|__|\|__|\|_______|\|__|\_________\ \|__|
|
||||
\|_________|
|
||||
`)
|
||||
}
|
||||
|
||||
// start server
|
||||
func start() {
|
||||
InitLog()
|
||||
printASC()
|
||||
if !conf.SkipUpdate {
|
||||
CheckUpdate()
|
||||
}
|
||||
if !ReadConf(conf.Con) {
|
||||
log.Errorf("读取配置文件时出现错误,启动失败.")
|
||||
return
|
||||
}
|
||||
InitClient()
|
||||
if !InitAliDrive() {
|
||||
log.Errorf("初始化阿里云盘出现错误,启动失败.")
|
||||
return
|
||||
}
|
||||
if !InitModel() {
|
||||
log.Errorf("初始化数据库出现错误,启动失败.")
|
||||
return
|
||||
}
|
||||
InitCron()
|
||||
server()
|
||||
}
|
||||
|
||||
// start http server
|
||||
func server() {
|
||||
baseServer := "0.0.0.0:" + conf.Conf.Server.Port
|
||||
r := gin.Default()
|
||||
serv.InitRouter(r)
|
||||
log.Infof("Starting server @ %s", baseServer)
|
||||
err := r.Run(baseServer)
|
||||
if err != nil {
|
||||
log.Errorf("Server failed start:%s", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// read config file
|
||||
func ReadConf(config string) bool {
|
||||
log.Infof("读取配置文件...")
|
||||
if !utils.Exists(config) {
|
||||
log.Infof("找不到配置文件:%s", config)
|
||||
return false
|
||||
}
|
||||
confFile, err := ioutil.ReadFile(config)
|
||||
if err != nil {
|
||||
log.Errorf("读取配置文件时发生错误:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
err = yaml.Unmarshal(confFile, conf.Conf)
|
||||
if err != nil {
|
||||
log.Errorf("加载配置文件时发生错误:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
log.Debugf("config:%+v", conf.Conf)
|
||||
conf.Origins = strings.Split(conf.Conf.Server.SiteUrl, ",")
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/alidrive"
|
||||
"github.com/robfig/cron/v3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Cron *cron.Cron
|
||||
|
||||
// refresh token func for cron
|
||||
func refreshToken() {
|
||||
alidrive.RefreshToken()
|
||||
}
|
||||
|
||||
// init cron jobs
|
||||
func InitCron() {
|
||||
log.Infof("初始化定时任务:刷新token")
|
||||
Cron = cron.New()
|
||||
_, err := Cron.AddFunc("@every 2h", refreshToken)
|
||||
if err != nil {
|
||||
log.Errorf("添加启动任务失败:%s", err.Error())
|
||||
}
|
||||
Cron.Start()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// init logrus
|
||||
func InitLog() {
|
||||
if conf.Debug {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
} else {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
ForceColors: true,
|
||||
EnvironmentOverrideColors: true,
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
FullTimestamp: true,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/server/models"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func InitModel() bool {
|
||||
log.Infof("初始化数据库...")
|
||||
switch conf.Conf.Database.Type {
|
||||
case "sqlite3":
|
||||
{
|
||||
if !(strings.HasSuffix(conf.Conf.Database.DBFile, ".db") && len(conf.Conf.Database.DBFile) > 3) {
|
||||
log.Errorf("db名称不正确.")
|
||||
return false
|
||||
}
|
||||
needMigrate := !utils.Exists(conf.Conf.Database.DBFile)
|
||||
db, err := gorm.Open(sqlite.Open(conf.Conf.Database.DBFile), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Errorf("连接数据库出现错误:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
conf.DB = db
|
||||
if needMigrate {
|
||||
log.Infof("迁移数据库...")
|
||||
err = conf.DB.AutoMigrate(&models.File{})
|
||||
if err != nil {
|
||||
log.Errorf("数据库迁移失败:%s", err.Error())
|
||||
return false
|
||||
}
|
||||
if err := models.BuildTree(); err != nil {
|
||||
log.Errorf("构建目录树失败:%s", err.Error())
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
default:
|
||||
log.Errorf("不支持的数据库类型:%s", conf.Conf.Database.Type)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Xhofe/alist/conf"
|
||||
"github.com/Xhofe/alist/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// github release response bean
|
||||
type GithubRelease struct {
|
||||
TagName string `json:"tag_name"`
|
||||
HtmlUrl string `json:"html_url"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// check update
|
||||
func CheckUpdate() {
|
||||
log.Infof("检查更新...")
|
||||
url := "https://api.github.com/repos/Xhofe/alist/releases/latest"
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Warnf("检查更新失败:%s", err.Error())
|
||||
return
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Warnf("读取更新内容失败:%s", err.Error())
|
||||
return
|
||||
}
|
||||
var release GithubRelease
|
||||
err = json.Unmarshal(body, &release)
|
||||
if err != nil {
|
||||
log.Warnf("解析更新失败:%s", err.Error())
|
||||
return
|
||||
}
|
||||
lasted := release.TagName[1:]
|
||||
now := conf.VERSION[1:]
|
||||
if utils.VersionCompare(lasted, now) != 1 {
|
||||
log.Infof("当前已是最新版本:%s", conf.VERSION)
|
||||
} else {
|
||||
log.Infof("发现新版本:%s", release.TagName)
|
||||
log.Infof("请至'%s'获取更新.", release.HtmlUrl)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user