Compare commits

..

76 Commits

Author SHA1 Message Date
微凉 f31fc9155a 🔖 release v1.0.5 2021-06-30 21:25:27 +08:00
微凉 d3db012dd0 🚡 move response struct 2021-06-30 21:13:29 +08:00
微凉 74b86ef5e5 🔧 修改每次请求文件数量 2021-06-30 19:32:38 +08:00
微凉 6be90429ad :anguished: remove sponsor 2021-06-30 11:28:22 +08:00
微凉 a6bbff2199 🎇 创建默认配置文件 2021-05-26 19:14:58 +08:00
微凉 3827d3ed67 Merge pull request #111 from daofeng2015/main
fix:api格式修改,新增加生成默认配置文件
2021-05-26 10:54:38 +08:00
daofeng e242867f41 fix:api格式修改,新增加生成默认配置文件 2021-05-26 00:50:37 +08:00
微凉 e09a75a87c ✨ close #109 文件夹软链接 2021-05-17 16:36:55 +08:00
微凉 e0a80b1477 Update README.md 2021-05-15 22:34:35 +08:00
微凉 d693e27ec0 🔖 release 1.0.4 2021-05-01 20:42:00 +08:00
微凉 b20f0717fe :bug: fix: #101 分次请求文件 2021-04-30 19:01:40 +08:00
微凉 427244d8d5 🎇 指定路径与深度rebuild 2021-04-14 13:34:14 +08:00
zsbai b613598c2b 在线预览视频时间延长到4小时 (#96)
* Update request.go

* Update req_bean.go
2021-04-13 23:37:20 +08:00
微凉 f0013320a6 🔖 release v1.0.3 2021-04-09 10:45:16 +08:00
微凉 974caf74d9 :fire: 只初始化一次client 2021-04-09 10:38:57 +08:00
Hello_海生 0bb02664c7 :bug: fix: #85 修复 x509: certificate signed by unknown authority (#86)
* 修复 x509: certificate signed by unknown authority

* 添加忽略证书验证
2021-04-09 10:30:03 +08:00
微凉 6c5a0cba6e :bug: 修复refresh_token失效时无限刷新的bug 2021-03-31 11:05:39 +08:00
微凉 7e21e12e11 👷 release增加Linux386 2021-03-31 09:08:06 +08:00
微凉 11489d8856 Merge pull request #68 from 122cygf/main
修复了因为Referer导致不能下载的问题
2021-03-31 08:04:51 +08:00
lzz 6d824a4ee9 Update auth.go 2021-03-31 00:23:51 +08:00
lzz 8d74d070d4 Update req_bean.go 2021-03-31 00:21:49 +08:00
Xhofe 77aae6660e ✨ 增加视频接口 2021-03-30 10:22:07 +08:00
微凉 76081a81a6 💚 linux_386构建出错 2021-03-21 10:31:53 +08:00
微凉 8760ab283d 💚 linux_386构建出错 2021-03-21 10:23:00 +08:00
微凉 61ab27398c 👷 添加linux386测试 2021-03-21 10:14:59 +08:00
微凉 2e64df7e3d Merge pull request #48 from phoon/main
自定义监听地址配置
2021-03-19 18:45:53 +08:00
Peven 9561f0c951 update conf.yml.example 2021-03-17 18:25:20 +08:00
Peven 03f5a54764 allow to set address in configuration file 2021-03-17 18:08:22 +08:00
微凉 9952c3e90b 💚 版本号 2021-03-17 13:01:02 +08:00
微凉 d94e319df3 🔖 release v1.0.1 2021-03-17 12:56:47 +08:00
微凉 b51b2deea1 💚 错误的文件名 2021-03-17 11:46:53 +08:00
微凉 7dda701f1e 💚 CI重复ID 2021-03-17 11:40:45 +08:00
微凉 3b93445648 👷 release ci surpoort cgo 2021-03-17 11:34:24 +08:00
微凉 a353081126 :bug: 重建时删除不完全 2021-03-16 23:52:41 +08:00
微凉 a5b2f998ab 🎇 支持mysql 2021-03-16 23:15:37 +08:00
微凉 4d0d892ce7 🎇 多盘支持 2021-03-16 21:25:16 +08:00
微凉 8e9ddcf81e :bug: fix: #43 直链密码错误 2021-03-16 16:25:02 +08:00
微凉 5c6344cac0 🎇 直链url密码哈希 2021-03-14 19:13:09 +08:00
微凉 7076efb6be 💚 降低构建系统版本 2021-03-13 23:04:13 +08:00
微凉 6d19b49a8d 🔖 release v1.0.0 2021-03-13 20:25:18 +08:00
微凉 4fa11879f2 :bug: 目录名 2021-03-12 22:03:50 +08:00
微凉 abe9d9237a 🚧 获取链接 2021-03-12 18:12:56 +08:00
微凉 e4d206d59c 🔹 删除list与get接口 2021-03-08 20:28:44 +08:00
微凉 8636014397 🚧 合并get与list 2021-03-08 20:26:02 +08:00
微凉 c0f50ffeff 🚧 参数校验 2021-03-07 21:51:26 +08:00
微凉 b677d6ad21 :heavy_minus_sign: 去除缓存 2021-03-07 21:02:56 +08:00
微凉 443067b80f 🚧 密码逻辑 2021-03-06 23:19:16 +08:00
微凉 3138e031f5 🐝 reformat code 2021-03-05 21:25:44 +08:00
微凉 d137ef8759 🚧 构建目录树 2021-03-05 21:07:45 +08:00
微凉 389226662c 🚧 添加model 2021-03-04 23:50:51 +08:00
微凉 9cb548d4f7 ⭐ 跳过检查更新 2021-02-27 20:06:09 +08:00
微凉 0e7083a713 Merge pull request #27 from 122cygf/main
⭐ 下载链接有效期延长到四小时
2021-02-26 13:14:55 +08:00
122cygf 46f09836f3 下载链接有效期延长到四小时 2021-02-26 12:37:44 +08:00
微凉 e146054679 📝 add notes 2021-02-04 10:02:34 +08:00
微凉 3b2a729dc6 🔧 修改配置文件 2021-01-22 14:27:03 +08:00
微凉 d18a752732 ✨ 添加了office接口 2021-01-19 17:20:14 +08:00
微凉 b9676182c9 🌿 优化了一些代码 2021-01-19 17:19:48 +08:00
微凉 434eb25408 ☁️ origin 2021-01-12 14:58:33 +08:00
微凉 858291876b 🉑 origin优化 2021-01-11 16:53:48 +08:00
微凉 dcebf5257f :bug: 多域名跨域 2021-01-08 16:32:02 +08:00
微凉 0cd4624a36 🆕 新版本 2021-01-05 16:51:31 +08:00
微凉 fcd9c59089 🔧 fix: #8 增加了多个文件预览 2021-01-05 16:40:02 +08:00
微凉 b394711859 ✨ 自定义脚本 2020-12-31 17:08:54 +08:00
微凉 495c3f25e9 🆕 检查更新 2020-12-31 16:15:15 +08:00
微凉 d5e3527bfb 🍃 去除文件缓存 2020-12-31 15:03:25 +08:00
微凉 ba7c33a2bb :bug: 配置名 2020-12-29 13:54:08 +08:00
微凉 bf3f741b22 🐎 加入缓存 2020-12-29 13:37:58 +08:00
微凉 02e665ae37 ✨ 多个自定义内容 2020-12-28 11:22:54 +08:00
微凉 bacbf7bc1b ✨ 文件301直链与password文件隐藏 2020-12-28 10:23:54 +08:00
微凉 4af469efed :bug: 时间超出int范围 2020-12-26 18:11:17 +08:00
微凉 52cddc431a 📝 添加教程 2020-12-25 19:12:27 +08:00
微凉 17f8c4ae1c :bug: 刷新token与跨域问题 2020-12-24 20:25:40 +08:00
微凉 070b6294cb 📝 更新Readme 2020-12-24 19:55:57 +08:00
微凉 c05c6b9a50 👷 自动版本发布 2020-12-24 15:27:37 +08:00
微凉 a7ce9451f3 🚧 添加了静态资源 2020-12-24 15:21:49 +08:00
微凉 430b4cf723 Initial commit 2020-12-24 01:39:45 +08:00
144 changed files with 2125 additions and 20529 deletions
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
-39
View File
@@ -1,39 +0,0 @@
name: "Bug report"
description: Bug report
labels: [pending triage]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: version
attributes:
label: Alist Version / Alist 版本
description: What version of our software are you running?
placeholder: v2.0.0
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: Describe the bug / 问题描述
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction / 复现链接
description: |
Please provide a link to a repo that can reproduce the problem you ran into.
请提供能复现此问题的链接
validations:
required: false
- type: textarea
id: logs
attributes:
label: 日志 / Logs
description: |
Please copy and paste any relevant log output.
请复制粘贴错误日志,或者截图
render: shell
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Discussions & Feature request
url: https://github.com/Xhofe/alist/discussions
about: Use GitHub discussions for message-board style questions and discussions or feature request.
+58 -27
View File
@@ -2,50 +2,81 @@ name: build
on:
push:
branches: [ v2 ]
branches: [ main ]
pull_request:
branches: [ v2 ]
branches: [ main ]
jobs:
build:
strategy:
matrix:
platform: [ubuntu-latest]
go-version: [1.17]
platform: [ubuntu-16.04]
go-version: [1.15]
name: Build
runs-on: ${{ matrix.platform }}
steps:
- name: Setup Go
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Checkout
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
ref: v2
path: alist
- name: Set up xgo
- name: Get dependencies
run: |
docker pull techknowlogick/xgo:latest
go install src.techknowlogick.com/xgo@latest
sudo apt install upx
- name: Build
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: |
mv alist/build.sh .
bash build.sh web
mv dist/* alist/public
bash build.sh build
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: Upload artifact
- 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: Build linux_386
run: |
sudo apt-get -y install libc6-dev-i386
CC=gcc CGO_ENABLED=1 GOOS=linux GOARCH=386 go build -o alist_linux_386 alist.go
- name: Upload artifacts linux_amd64
uses: actions/upload-artifact@v2
with:
name: artifact
path: alist/build
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
- name: Upload artifacts linux_386
uses: actions/upload-artifact@v2
with:
name: alist_linux_386
path: alist_linux_386
-46
View File
@@ -1,46 +0,0 @@
name: build_docker
on:
push:
branches: [ v2 ]
pull_request:
branches: [ v2 ]
jobs:
build_docker:
name: Docker
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: xhofe/alist
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Build web
run: |
bash build.sh web
mv dist/* public
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: xhofe
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
+111 -23
View File
@@ -1,5 +1,4 @@
name: release
on:
push:
tags:
@@ -9,38 +8,127 @@ jobs:
release:
strategy:
matrix:
platform: [ubuntu-latest]
go-version: [1.17]
name: Release
platform: [ ubuntu-16.04 ]
go-version: [ 1.15 ]
name: Build
runs-on: ${{ matrix.platform }}
steps:
- name: Setup Go
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout
- name: Get version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
ref: v2
path: alist
persist-credentials: false
fetch-depth: 0
- name: Set up xgo
- name: Get dependencies
run: |
docker pull techknowlogick/xgo:latest
go install src.techknowlogick.com/xgo@latest
sudo apt install upx
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
- name: Build linux
run: |
mv alist/build.sh .
bash build.sh cdn
mv dist/* alist/public
bash build.sh release
CC=gcc CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o linux_amd64/alist alist.go
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o linux_arm64/alist alist.go
CC=arm-linux-gnueabihf-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm go build -o linux_arm/alist alist.go
- name: Release
uses: softprops/action-gh-release@v1
- name: Build windows
run: |
CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o windows_amd64/alist.exe alist.go
- name: Build linux_386
run: |
sudo apt-get -y install libc6-dev-i386
CC=gcc CGO_ENABLED=1 GOOS=linux GOARCH=386 go build -o linux_386/alist alist.go
- name: compress
run: |
tar -czvf alist_linux_amd64.tar.gz linux_amd64/alist conf.yml.example
tar -czvf alist_linux_arm64.tar.gz linux_arm64/alist conf.yml.example
tar -czvf alist_linux_arm.tar.gz linux_arm/alist conf.yml.example
tar -czvf alist_linux_386.tar.gz linux_386/alist conf.yml.example
zip alist_windows_amd64.zip windows_amd64/alist.exe conf.yml.example
- name: Build Changelog
id: github_release
uses: mikepenz/release-changelog-builder-action@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: alist/build/compress/*
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: ${{steps.github_release.outputs.changelog}}
draft: false
prerelease: false
- name: Upload alist_linux_amd64
id: upload-release-linux-amd64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: alist_linux_amd64.tar.gz
asset_name: alist_${{ steps.get_version.outputs.VERSION }}_linux_amd64.tar.gz
asset_content_type: application/gzip
- name: Upload alist_linux_arm64
id: upload-release-linux-arm64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: alist_linux_arm64.tar.gz
asset_name: alist_${{ steps.get_version.outputs.VERSION }}_linux_arm64.tar.gz
asset_content_type: application/gzip
- name: Upload alist_linux_arm
id: upload-release-linux-arm
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: alist_linux_arm.tar.gz
asset_name: alist_${{ steps.get_version.outputs.VERSION }}_linux_arm.tar.gz
asset_content_type: application/gzip
- name: Upload alist_linux_386
id: upload-release-linux-386
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: alist_linux_386.tar.gz
asset_name: alist_${{ steps.get_version.outputs.VERSION }}_linux_386.tar.gz
asset_content_type: application/gzip
- name: Upload alist_windows_amd64
id: upload-release-windows-amd64
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: alist_windows_amd64.zip
asset_name: alist_${{ steps.get_version.outputs.VERSION }}_windows_amd64.zip
asset_content_type: application/zip
-45
View File
@@ -1,45 +0,0 @@
name: release_docker
on:
push:
tags:
- '*'
jobs:
docker_release:
name: Docker
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: xhofe/alist
- name: Set up Node
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Build web
run: |
bash build.sh cdn
mv dist/* public
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: xhofe
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
+2 -6
View File
@@ -20,10 +20,6 @@ dist/
# Dependency directories (remove the comment below to include it)
# vendor/
*.yml
bin/*
/alist
*.json
public/*.html
public/assets/
public/public/
data/
alist
-14
View File
@@ -1,14 +0,0 @@
FROM alpine:edge as builder
LABEL stage=go-builder
WORKDIR /app/
COPY ./ ./
RUN apk add --no-cache bash git go gcc musl-dev; \
bash build.sh docker
FROM alpine:edge
LABEL MAINTAINER="i@nn.ci"
VOLUME /opt/alist/data/
WORKDIR /opt/alist/
COPY --from=builder /app/bin/alist ./
EXPOSE 5244
CMD [ "./alist" ]
+21 -661
View File
File diff suppressed because it is too large Load Diff
Executable → Regular
+44 -55
View File
@@ -1,75 +1,64 @@
<div align="center">
<h3><a href="https://alist.nn.ci">Alist</a></h3>
<p><em>🗂️Another file list program that supports multiple storage, powered by Gin and React.</em></p>
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="latest version"></a>
<a href="https://github.com/Xhofe/alist/discussions"><img src="https://img.shields.io/github/discussions/Xhofe/alist?color=%23ED8936&style=flat-square" alt="discussions"></a>
<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&color=%239F7AEA" alt="Downloads"></a>
<a href="https://github.com/Xhofe/alist/blob/v2/LICENSE"><img src="https://img.shields.io/github/license/Xhofe/alist?style=flat-square" alt="License"></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>
</div>
</p>
---
English | [中文](./README_cn.md)
### 这是什么?
## Features
一款阿里云盘的目录文件列表程序,后端基于`golang`最好的`http`框架`gin`,前端使用`vue`和`ant design`。
- [x] Multiple storage
- [x] Local storage
- [x] [Aliyundrive](https://www.aliyundrive.com/)
- [x] OneDrive / Sharepoint ([global](https://www.office.com/), [cn](https://portal.partner.microsoftonline.cn),de,us)
- [x] [189cloud](https://cloud.189.cn)
- [x] [GoogleDrive](https://drive.google.com/)
- [x] [123pan](https://www.123pan.com/)
- [x] [Lanzou](https://pc.woozooo.com/)
- [x] [Alist](https://github.com/Xhofe/alist)
- [x] FTP
- [x] [PikPak](https://www.mypikpak.com/)
- [x] [ShandianPan](https://shandianpan.com/)
- [x] [S3](https://aws.amazon.com/s3/)
- [x] WebDav
- [x] Teambition([China](https://www.teambition.com/ ),[International](https://us.teambition.com/ ))
- [x] [Mediatrack](https://www.mediatrack.cn/)
- [x] [139yun](https://yun.139.com/) (Personal, Family)
- [x] Easy to deploy and out-of-the-box
- [x] File preview (PDF, markdown, code, plain text, ...)
- [x] Image preview in gallery mode
- [x] Video and audio preview (mp4, mp3, ...)
- [x] Office documents preview (docx, pptx, xlsx, ...)
- [x] `README.md` preview rendering
- [x] File permalink copy and direct file download
- [x] Dark mode
- [x] I18n
- [x] Protected routes (password protection and authentication)
- [x] WebDav (see https://alist-doc.nn.ci/en/docs/webdav for details)
- [x] [Docker Deploy](https://hub.docker.com/r/xhofe/alist)
- [x] Cloudflare workers proxy
- [x] File/Folder package download
- [x] Support video list playback and subtitles(ass,srt,vtt)
- [x] Web upload(Can allow visitors to upload), delete, mkdir, rename, move and copy
### 前端项目地址
## Discussion
- https://github.com/Xhofe/alist-web
Please go to our [discussion forum](https://github.com/Xhofe/alist/discussions) for general questions, **issues are for bug reports only.**
### 演示地址
## Demo
- https://alist.nn.ci (稳定版本)
- https://alist.now.sh (开发版本)
- https://alist-plyr.now.sh (plyr分支版本)
Available at: <https://alist.nn.ci>.
### 预览
![demo](https://inews.gtimg.com/newsapp_ls/0/14256614096/0)
<a href="https://alist.nn.ci/"><img src="https://img.oez.cc/2020/12/24/d81d2dab3e5f0.png"></a>
## Document
### 支持的功能
<https://alist-doc.nn.ci/en/>
- 自动刷新`token`,`refresh_token`自动更新,失效时间未知,本人使用过程中没有失效过。
- 图片、视频、音频预览
- 目录加密
- `Readme`渲染
- 自定义根目录
- 文件直链下载
- …
## License
#### TODO
The `AList` is open-source software licensed under the AGPL-3.0 license.
- [x] 排序
- [x] 文件预览
- [x] 图片
- [x] 视频
- [x] 音频
- [x] `Readme`渲染
- [x] 密码加密
- [ ] 搜索与翻页
- [x] 文件直链
- [ ] 路径优化
- [x] 缓存
---
### 如何使用
> [@Blog](https://www.nn.ci/) · [@GitHub](https://github.com/Xhofe)
- https://www.nn.ci/archives/alist.html
### License
The `AList` is open-source software licensed under the MIT license.
-74
View File
@@ -1,74 +0,0 @@
<div align="center">
<h3><a href="https://alist.nn.ci">Alist</a></h3>
<p><em>🗂️一个支持多存储的文件列表程序,使用 Gin 和 React 。</em></p>
<a href="https://github.com/Xhofe/alist/releases"><img src="https://img.shields.io/github/release/Xhofe/alist?style=flat-square" alt="latest version"></a>
<a href="https://github.com/Xhofe/alist/discussions"><img src="https://img.shields.io/github/discussions/Xhofe/alist?color=%23ED8936&style=flat-square" alt="discussions"></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&color=%239F7AEA" alt="Downloads"></a>
<a href="https://github.com/Xhofe/alist/blob/v2/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>
</div>
---
[English](./README.md) | 中文
## 支持
- [x] 多种存储
- [x] 本地存储
- [x] [阿里云盘](https://www.aliyundrive.com/)
- [x] OneDrive / Sharepoint([国际版](https://www.office.com/), [世纪互联](https://portal.partner.microsoftonline.cn),de,us)
- [x] [天翼云盘](https://cloud.189.cn)
- [x] [GoogleDrive](https://drive.google.com/)
- [x] [123云盘](https://www.123pan.com/)
- [x] [蓝奏云](https://pc.woozooo.com/)
- [x] [Alist](https://github.com/Xhofe/alist)
- [x] FTP
- [x] [PikPak](https://www.mypikpak.com/)
- [x] [闪电盘](https://shandianpan.com/)
- [x] [S3](https://aws.amazon.com/cn/s3/)
- [x] WebDav
- [x] Teambition([中国](https://www.teambition.com/ ),[国际](https://us.teambition.com/ ))
- [x] [分秒帧](https://www.mediatrack.cn/)
- [x] [和彩云](https://yun.139.com/) (个人云, 家庭云)
- [x] 部署方便,开箱即用
- [x] 文件预览(PDF、markdown、代码、纯文本……)
- [x] 画廊模式下的图像预览
- [x] 视频和音频预览(mp4、mp3 等)
- [x] Office 文档预览(docx、pptx、xlsx、...)
- [x] `README.md` 预览渲染
- [x] 文件永久链接复制和直接文件下载
- [x] 黑暗模式
- [x] 国际化
- [x] 受保护的路由(密码保护和身份验证)
- [x] WebDav(具体见https://alist-doc.nn.ci/docs/webdav )
- [x] [Docker 部署](https://hub.docker.com/r/xhofe/alist)
- [x] Cloudflare workers 中转
- [x] 文件/文件夹打包下载
- [x] 支持视频列表播放和字幕(ass,srt,vtt)
- [x] 网页上传(可以允许访客上传),删除,新建文件夹,重命名,移动,复制
## 讨论
一般问题请到[讨论论坛](https://github.com/Xhofe/alist/discussions) ,**issue仅针对错误报告。**
## 演示
<https://alist.nn.ci>。
![演示](https://inews.gtimg.com/newsapp_ls/0/14256614096/0)
## 文档
<https://alist-doc.nn.ci/>
## 许可
`AList` 是在 AGPL-3.0 许可下许可的开源软件。
---
> [@Blog](https://www.nn.ci/) · [@GitHub](https://github.com/Xhofe)
+49
View File
@@ -0,0 +1,49 @@
package alidrive
import (
"encoding/json"
"github.com/Xhofe/alist/conf"
"github.com/Xhofe/alist/utils"
log "github.com/sirupsen/logrus"
)
// refresh access_token token by refresh_token
func RefreshToken(drive *conf.Drive) bool {
log.Infof("刷新[%s]token...", drive.Name)
url := "https://auth.aliyundrive.com/v2/account/token"
req := RefreshTokenReq{RefreshToken: drive.RefreshToken , GrantType: "refresh_token"}
var token TokenResp
if body, err := DoPost(url, req, ""); 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解析失败应该是[%s]refresh_token失效", drive.Name)
return false
}
}
if token.Code != "" {
log.Errorf("盘[%s]刷新token出错:%s", drive.Name, token.Message)
return false
}
//刷新成功 更新token
drive.AccessToken = token.AccessToken
drive.RefreshToken = token.RefreshToken
return true
}
func RefreshTokenAll() string {
log.Infof("刷新所有token...")
res := ""
for i, drive := range conf.Conf.AliDrive.Drives {
if !RefreshToken(&conf.Conf.AliDrive.Drives[i]) {
res = res + drive.Name + ","
}
}
utils.WriteToYml(conf.ConfigFile, conf.Conf)
if res != "" {
return res[:len(res)-1]
}
return ""
}
+80
View File
@@ -0,0 +1,80 @@
package alidrive
import (
"bytes"
"encoding/json"
"fmt"
"github.com/Xhofe/alist/conf"
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
"strings"
"time"
)
// convert body to json
func BodyToJson(url string, req interface{}, resp RespHandle, drive *conf.Drive) error {
if body, err := DoPost(url, req, drive.AccessToken); err != nil {
log.Errorf("doPost出错:%s", err.Error())
return err
} else {
if err = json.Unmarshal(body, &resp); err != nil {
log.Errorf("解析json[%s]出错:%s", string(body), err.Error())
return err
}
}
if resp.IsAvailable() {
return nil
}
if resp.GetCode() == conf.AccessTokenInvalid {
resp.SetCode("")
if RefreshToken(drive) {
return BodyToJson(url, req, resp, drive)
}
}
return fmt.Errorf(resp.GetMessage())
}
// do post request
func DoPost(url string, request interface{}, auth string) (body []byte, err error) {
var (
resp *http.Response
)
requestBody := new(bytes.Buffer)
err = json.NewEncoder(requestBody).Encode(request)
if err != nil {
log.Errorf("创建requestBody出错:%s", err.Error())
}
req, err := http.NewRequest("POST", url, requestBody)
log.Debugf("do_post_req:%+v", req)
if err != nil {
log.Errorf("创建request出错:%s", err.Error())
return
}
if auth != "" {
req.Header.Set("authorization", conf.Bearer+auth)
}
req.Header.Add("content-type", "application/json")
req.Header.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36")
req.Header.Add("origin", "https://aliyundrive.com")
req.Header.Add("accept", "*/*")
req.Header.Add("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")
req.Header.Add("Connection", "keep-alive")
for retryCount := 3; retryCount >= 0; retryCount-- {
if resp, err = conf.Client.Do(req); err != nil && strings.Contains(err.Error(), "timeout") {
<-time.After(time.Second)
} else {
break
}
}
if err != nil {
log.Errorf("请求阿里云盘api时出错:%s", err.Error())
return
}
if body, err = ioutil.ReadAll(resp.Body); err != nil {
log.Errorf("读取api返回内容失败")
}
log.Debugf("请求返回信息:%s", string(body))
return
}
+75
View File
@@ -0,0 +1,75 @@
package alidrive
// ListReq 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"`
}
// GetReq 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"`
}
// DownloadReq 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"`
}
// SearchReq 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"`
}
// TokenLoginReq token_login request bean
type TokenLoginReq struct {
Token string `json:"token"`
}
// GetTokenReq get_token request bean
type GetTokenReq struct {
Code string `json:"code"`
}
// RefreshTokenReq refresh_token request bean
type RefreshTokenReq struct {
RefreshToken string `json:"refresh_token"`
GrantType string `json:"grant_type"`
}
// OfficePreviewUrlReq office_preview_url request bean
type OfficePreviewUrlReq struct {
AccessToken string `json:"access_token"`
DriveId string `json:"drive_id"`
FileId string `json:"file_id"`
}
// VideoPreviewUrlReq video preview url request bean
type VideoPreviewUrlReq struct {
DriveId string `json:"drive_id"`
FileId string `json:"file_id"`
ExpireSec int `json:"expire_sec"`
}
+124
View File
@@ -0,0 +1,124 @@
package alidrive
import (
"fmt"
"github.com/Xhofe/alist/conf"
)
// get file
func GetFile(fileId string, drive *conf.Drive) (*File, error) {
url := conf.Conf.AliDrive.ApiUrl + "/file/get"
req := GetReq{
DriveId: drive.DefaultDriveId,
FileId: fileId,
ImageThumbnailProcess: conf.ImageThumbnailProcess,
VideoThumbnailProcess: conf.VideoThumbnailProcess,
}
var resp File
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// get download_url
func GetDownLoadUrl(fileId string, drive *conf.Drive) (*DownloadResp, error) {
url := conf.Conf.AliDrive.ApiUrl + "/file/get_download_url"
req := DownloadReq{
DriveId: drive.DefaultDriveId,
FileId: fileId,
ExpireSec: 14400,
}
var resp DownloadResp
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// search by keyword
func Search(key string, limit int, marker string, drive *conf.Drive) (*Files, error) {
url := conf.Conf.AliDrive.ApiUrl + "/file/search"
req := SearchReq{
DriveId: drive.DefaultDriveId,
ImageThumbnailProcess: conf.ImageThumbnailProcess,
ImageUrlProcess: conf.ImageUrlProcess,
Limit: limit,
Marker: marker,
OrderBy: conf.OrderSearch,
Query: fmt.Sprintf("name match '%s'", key),
VideoThumbnailProcess: conf.VideoThumbnailProcess,
}
var resp Files
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// get root folder
func GetRoot(limit int, marker string, orderBy string, orderDirection string, drive *conf.Drive) (*Files, error) {
return GetList(drive.RootFolder, limit, marker, orderBy, orderDirection, drive)
}
// get folder list by file_id
func GetList(parent string, limit int, marker string, orderBy string, orderDirection string, drive *conf.Drive) (*Files, error) {
url := conf.Conf.AliDrive.ApiUrl + "/file/list"
req := ListReq{
DriveId: drive.DefaultDriveId,
Fields: "*",
ImageThumbnailProcess: conf.ImageThumbnailProcess,
ImageUrlProcess: conf.ImageUrlProcess,
Limit: limit,
Marker: marker,
OrderBy: orderBy,
OrderDirection: orderDirection,
ParentFileId: parent,
VideoThumbnailProcess: conf.VideoThumbnailProcess,
}
var resp Files
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// get user info
func GetUserInfo(drive *conf.Drive) (*UserInfo, error) {
url := conf.Conf.AliDrive.ApiUrl + "/user/get"
var resp UserInfo
if err := BodyToJson(url, map[string]interface{}{}, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// get office preview url and token
func GetOfficePreviewUrl(fileId string, drive *conf.Drive) (*OfficePreviewUrlResp, error) {
url := conf.Conf.AliDrive.ApiUrl + "/file/get_office_preview_url"
req := OfficePreviewUrlReq{
AccessToken: drive.AccessToken,
DriveId: drive.DefaultDriveId,
FileId: fileId,
}
var resp OfficePreviewUrlResp
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
// get video preview url
func GetVideoPreviewUrl(fileId string, drive *conf.Drive) (*VideoPreviewUrlResp, error) {
url := conf.Conf.AliDrive.ApiUrl + "/databox/get_video_play_info"
req := VideoPreviewUrlReq{
DriveId: drive.DefaultDriveId,
FileId: fileId,
ExpireSec: 14400,
}
var resp VideoPreviewUrlResp
if err := BodyToJson(url, req, &resp, drive); err != nil {
return nil, err
}
return &resp, nil
}
+164
View File
@@ -0,0 +1,164 @@
package alidrive
import (
"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"`
}
/** 秒传
{
"name":"mikuclub.mp4",
"content_hash":"C733AC50D1F964C0398D0E403F3A30C37EFC2ADD",
"size":1141068377,
"content_type":"video/mp4"
}
*/
// 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"`
}
type VideoPreviewUrlResp struct {
RespError
TemplateList []struct {
TemplateId string `json:"template_id"`
Status string `json:"status"`
Url string `json:"url"`
} `json:"template_list"`
}
+41
View File
@@ -0,0 +1,41 @@
package alidrive
import (
log "github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
"strings"
)
// 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 ""
}
+4 -55
View File
@@ -1,59 +1,8 @@
package main
import (
"fmt"
"github.com/Xhofe/alist/bootstrap"
"github.com/Xhofe/alist/conf"
_ "github.com/Xhofe/alist/drivers"
"github.com/Xhofe/alist/model"
"github.com/Xhofe/alist/server"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)
func Init() bool {
//bootstrap.InitLog()
bootstrap.InitConf()
bootstrap.InitCron()
bootstrap.InitModel()
if conf.Password {
pass, err := model.GetSettingByKey("password")
if err != nil {
log.Errorf(err.Error())
return false
}
log.Infof("current password: %s", pass.Value)
return false
}
server.InitIndex()
bootstrap.InitSettings()
bootstrap.InitAccounts()
bootstrap.InitCache()
return true
}
import "github.com/Xhofe/alist/bootstrap"
// main function
func main() {
if conf.Version {
fmt.Printf("Built At: %s\nGo Version: %s\nAuthor: %s\nCommit ID: %s\nVersion: %s\n", conf.BuiltAt, conf.GoVersion, conf.GitAuthor, conf.GitCommit, conf.GitTag)
return
}
if !Init() {
return
}
if !conf.Debug {
gin.SetMode(gin.ReleaseMode)
}
r := gin.Default()
server.InitApiRouter(r)
base := fmt.Sprintf("%s:%d", conf.Conf.Address, conf.Conf.Port)
log.Infof("start server @ %s", base)
var err error
if conf.Conf.Scheme.Https {
err = r.RunTLS(base, conf.Conf.Scheme.CertFile, conf.Conf.Scheme.KeyFile)
} else {
err = r.Run(base)
}
if err != nil {
log.Errorf("failed to start: %s", err.Error())
}
}
bootstrap.Run()
}
-12
View File
@@ -1,12 +0,0 @@
package main
import (
"fmt"
"net/url"
"testing"
)
func TestUrl(t *testing.T) {
s,_ := url.QueryUnescape("/ali/%E7%8C%AA%E5%A4%B4%E7%9A%84%E6%96%87%E4%BB%B6%5B%E5%98%BF%E5%98%BF%5D/%E9%82%B9%E9%82%B9%E7%9A%84%E6%96%87%E4%BB%B6/%E6%A1%8C%E9%9D%A2%E5%A3%81%E7%BA%B8/v2-e8f266ba17ae387eefed1cb22b2b5e4e_r.jpg")
fmt.Print(s)
}

Some files were not shown because too many files have changed in this diff Show More