Compare commits
8 Commits
feat/ilanz
...
v3.30.0
Author | SHA1 | Date | |
---|---|---|---|
e6e2d03ba1 | |||
28bb3f6310 | |||
fb729c1846 | |||
4448e08f5b | |||
8020d42b10 | |||
9d5fb7f595 | |||
126cfe9f93 | |||
fd96a7ccf4 |
26
.github/workflows/build_docker.yml
vendored
26
.github/workflows/build_docker.yml
vendored
@ -3,6 +3,8 @@ name: build_docker
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
@ -10,42 +12,54 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_docker:
|
build_docker:
|
||||||
name: Build docker
|
name: Build Docker
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
|
||||||
|
- name: Build go binary
|
||||||
|
run: bash build.sh dev docker-multiplatform
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: xhofe/alist
|
images: xhofe/alist
|
||||||
- name: Replace release with dev
|
|
||||||
run: |
|
|
||||||
sed -i 's/release/dev/g' Dockerfile
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
|
if: github.event_name == 'push'
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: xhofe
|
username: xhofe
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
file: Dockerfile.ci
|
||||||
|
push: ${{ github.event_name == 'push' }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
|
||||||
|
|
||||||
build_docker_with_aria2:
|
build_docker_with_aria2:
|
||||||
needs: build_docker
|
needs: build_docker
|
||||||
name: Build docker with aria2
|
name: Build docker with aria2
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'push'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
8
.github/workflows/release_docker.yml
vendored
8
.github/workflows/release_docker.yml
vendored
@ -13,6 +13,13 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
|
||||||
|
- name: Build go binary
|
||||||
|
run: bash build.sh release docker-multiplatform
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
@ -36,6 +43,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
file: Dockerfile.ci
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
15
Dockerfile
15
Dockerfile
@ -1,9 +1,11 @@
|
|||||||
FROM alpine:edge as builder
|
FROM alpine:edge as builder
|
||||||
LABEL stage=go-builder
|
LABEL stage=go-builder
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
|
RUN apk add --no-cache bash curl gcc git go musl-dev
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
RUN apk add --no-cache bash curl gcc git go musl-dev; \
|
RUN bash build.sh release docker
|
||||||
bash build.sh release docker
|
|
||||||
|
|
||||||
FROM alpine:edge
|
FROM alpine:edge
|
||||||
LABEL MAINTAINER="i@nn.ci"
|
LABEL MAINTAINER="i@nn.ci"
|
||||||
@ -11,8 +13,11 @@ VOLUME /opt/alist/data/
|
|||||||
WORKDIR /opt/alist/
|
WORKDIR /opt/alist/
|
||||||
COPY --from=builder /app/bin/alist ./
|
COPY --from=builder /app/bin/alist ./
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
RUN apk add --no-cache bash ca-certificates su-exec tzdata; \
|
RUN apk update && \
|
||||||
chmod +x /entrypoint.sh
|
apk upgrade --no-cache && \
|
||||||
|
apk add --no-cache bash ca-certificates su-exec tzdata; \
|
||||||
|
chmod +x /entrypoint.sh && \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
ENV PUID=0 PGID=0 UMASK=022
|
ENV PUID=0 PGID=0 UMASK=022
|
||||||
EXPOSE 5244 5245
|
EXPOSE 5244 5245
|
||||||
CMD [ "/entrypoint.sh" ]
|
CMD [ "/entrypoint.sh" ]
|
16
Dockerfile.ci
Normal file
16
Dockerfile.ci
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
FROM alpine:edge
|
||||||
|
ARG TARGETPLATFORM
|
||||||
|
LABEL MAINTAINER="i@nn.ci"
|
||||||
|
VOLUME /opt/alist/data/
|
||||||
|
WORKDIR /opt/alist/
|
||||||
|
COPY /${TARGETPLATFORM}/alist ./
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN apk update && \
|
||||||
|
apk upgrade --no-cache && \
|
||||||
|
apk add --no-cache bash ca-certificates su-exec tzdata; \
|
||||||
|
chmod +x /entrypoint.sh && \
|
||||||
|
rm -rf /var/cache/apk/* && \
|
||||||
|
/entrypoint.sh version
|
||||||
|
ENV PUID=0 PGID=0 UMASK=022
|
||||||
|
EXPOSE 5244 5245
|
||||||
|
CMD [ "/entrypoint.sh" ]
|
@ -66,6 +66,7 @@ English | [中文](./README_cn.md)| [日本語](./README_ja.md) | [Contributing]
|
|||||||
- [x] [Quark](https://pan.quark.cn)
|
- [x] [Quark](https://pan.quark.cn)
|
||||||
- [x] [Thunder](https://pan.xunlei.com)
|
- [x] [Thunder](https://pan.xunlei.com)
|
||||||
- [x] [Lanzou](https://www.lanzou.com/)
|
- [x] [Lanzou](https://www.lanzou.com/)
|
||||||
|
- [x] [ILanzou](https://www.ilanzou.com/)
|
||||||
- [x] [Aliyundrive share](https://www.alipan.com/)
|
- [x] [Aliyundrive share](https://www.alipan.com/)
|
||||||
- [x] [Google photo](https://photos.google.com/)
|
- [x] [Google photo](https://photos.google.com/)
|
||||||
- [x] [Mega.nz](https://mega.nz)
|
- [x] [Mega.nz](https://mega.nz)
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
- [x] [夸克网盘](https://pan.quark.cn)
|
- [x] [夸克网盘](https://pan.quark.cn)
|
||||||
- [x] [迅雷网盘](https://pan.xunlei.com)
|
- [x] [迅雷网盘](https://pan.xunlei.com)
|
||||||
- [x] [蓝奏云](https://www.lanzou.com/)
|
- [x] [蓝奏云](https://www.lanzou.com/)
|
||||||
|
- [x] [蓝奏云优享版](https://www.ilanzou.com/)
|
||||||
- [x] [阿里云盘分享](https://www.alipan.com/)
|
- [x] [阿里云盘分享](https://www.alipan.com/)
|
||||||
- [x] [谷歌相册](https://photos.google.com/)
|
- [x] [谷歌相册](https://photos.google.com/)
|
||||||
- [x] [Mega.nz](https://mega.nz)
|
- [x] [Mega.nz](https://mega.nz)
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
- [x] [Quark](https://pan.quark.cn)
|
- [x] [Quark](https://pan.quark.cn)
|
||||||
- [x] [Thunder](https://pan.xunlei.com)
|
- [x] [Thunder](https://pan.xunlei.com)
|
||||||
- [x] [Lanzou](https://www.lanzou.com/)
|
- [x] [Lanzou](https://www.lanzou.com/)
|
||||||
|
- [x] [ILanzou](https://www.ilanzou.com/)
|
||||||
- [x] [Aliyundrive share](https://www.alipan.com/)
|
- [x] [Aliyundrive share](https://www.alipan.com/)
|
||||||
- [x] [Google photo](https://photos.google.com/)
|
- [x] [Google photo](https://photos.google.com/)
|
||||||
- [x] [Mega.nz](https://mega.nz)
|
- [x] [Mega.nz](https://mega.nz)
|
||||||
|
55
build.sh
55
build.sh
@ -85,12 +85,61 @@ BuildDev() {
|
|||||||
cat md5.txt
|
cat md5.txt
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildDocker() {
|
PrepareBuildDocker() {
|
||||||
echo "replace github.com/mattn/go-sqlite3 => github.com/leso-kn/go-sqlite3 v0.0.0-20230710125852-03158dc838ed" >>go.mod
|
echo "replace github.com/mattn/go-sqlite3 => github.com/leso-kn/go-sqlite3 v0.0.0-20230710125852-03158dc838ed" >>go.mod
|
||||||
go get gorm.io/driver/sqlite@v1.4.4
|
go get gorm.io/driver/sqlite@v1.4.4
|
||||||
|
go mod download
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildDocker() {
|
||||||
|
PrepareBuildDocker
|
||||||
go build -o ./bin/alist -ldflags="$ldflags" -tags=jsoniter .
|
go build -o ./bin/alist -ldflags="$ldflags" -tags=jsoniter .
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuildDockerMultiplatform() {
|
||||||
|
PrepareBuildDocker
|
||||||
|
|
||||||
|
BASE="https://musl.cc/"
|
||||||
|
FILES=(x86_64-linux-musl-cross aarch64-linux-musl-cross i486-linux-musl-cross s390x-linux-musl-cross armv6-linux-musleabihf-cross armv7l-linux-musleabihf-cross)
|
||||||
|
for i in "${FILES[@]}"; do
|
||||||
|
url="${BASE}${i}.tgz"
|
||||||
|
curl -L -o "${i}.tgz" "${url}"
|
||||||
|
sudo tar xf "${i}.tgz" --strip-components 1 -C /usr/local
|
||||||
|
rm -f "${i}.tgz"
|
||||||
|
done
|
||||||
|
|
||||||
|
docker_lflags="--extldflags '-static -fpic' $ldflags"
|
||||||
|
export CGO_ENABLED=1
|
||||||
|
|
||||||
|
OS_ARCHES=(linux-amd64 linux-arm64 linux-386 linux-s390x)
|
||||||
|
CGO_ARGS=(x86_64-linux-musl-gcc aarch64-linux-musl-gcc i486-linux-musl-gcc s390x-linux-musl-gcc)
|
||||||
|
for i in "${!OS_ARCHES[@]}"; do
|
||||||
|
os_arch=${OS_ARCHES[$i]}
|
||||||
|
cgo_cc=${CGO_ARGS[$i]}
|
||||||
|
os=${os_arch%%-*}
|
||||||
|
arch=${os_arch##*-}
|
||||||
|
export GOOS=$os
|
||||||
|
export GOARCH=$arch
|
||||||
|
export CC=${cgo_cc}
|
||||||
|
echo "building for $os_arch"
|
||||||
|
go build -o ./$os/$arch/alist -ldflags="$docker_lflags" -tags=jsoniter .
|
||||||
|
done
|
||||||
|
|
||||||
|
DOCKER_ARM_ARCHES=(linux-arm/v6 linux-arm/v7)
|
||||||
|
CGO_ARGS=(armv6-linux-musleabihf-gcc armv7l-linux-musleabihf-gcc)
|
||||||
|
GO_ARM=(6 7)
|
||||||
|
export GOOS=linux
|
||||||
|
export GOARCH=arm
|
||||||
|
for i in "${!DOCKER_ARM_ARCHES[@]}"; do
|
||||||
|
docker_arch=${DOCKER_ARM_ARCHES[$i]}
|
||||||
|
cgo_cc=${CGO_ARGS[$i]}
|
||||||
|
export GOARM=${GO_ARM[$i]}
|
||||||
|
export CC=${cgo_cc}
|
||||||
|
echo "building for $docker_arch"
|
||||||
|
go build -o ./${docker_arch%%-*}/${docker_arch##*-}/alist -ldflags="$docker_lflags" -tags=jsoniter .
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
BuildRelease() {
|
BuildRelease() {
|
||||||
rm -rf .git/
|
rm -rf .git/
|
||||||
mkdir -p "build"
|
mkdir -p "build"
|
||||||
@ -190,6 +239,8 @@ if [ "$1" = "dev" ]; then
|
|||||||
FetchWebDev
|
FetchWebDev
|
||||||
if [ "$2" = "docker" ]; then
|
if [ "$2" = "docker" ]; then
|
||||||
BuildDocker
|
BuildDocker
|
||||||
|
elif [ "$2" = "docker-multiplatform" ]; then
|
||||||
|
BuildDockerMultiplatform
|
||||||
else
|
else
|
||||||
BuildDev
|
BuildDev
|
||||||
fi
|
fi
|
||||||
@ -197,6 +248,8 @@ elif [ "$1" = "release" ]; then
|
|||||||
FetchWebRelease
|
FetchWebRelease
|
||||||
if [ "$2" = "docker" ]; then
|
if [ "$2" = "docker" ]; then
|
||||||
BuildDocker
|
BuildDocker
|
||||||
|
elif [ "$2" = "docker-multiplatform" ]; then
|
||||||
|
BuildDockerMultiplatform
|
||||||
elif [ "$2" = "linux_musl_arm" ]; then
|
elif [ "$2" = "linux_musl_arm" ]; then
|
||||||
BuildReleaseLinuxMuslArm
|
BuildReleaseLinuxMuslArm
|
||||||
MakeRelease "md5-linux-musl-arm.txt"
|
MakeRelease "md5-linux-musl-arm.txt"
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
_ "github.com/alist-org/alist/v3/drivers/ftp"
|
_ "github.com/alist-org/alist/v3/drivers/ftp"
|
||||||
_ "github.com/alist-org/alist/v3/drivers/google_drive"
|
_ "github.com/alist-org/alist/v3/drivers/google_drive"
|
||||||
_ "github.com/alist-org/alist/v3/drivers/google_photo"
|
_ "github.com/alist-org/alist/v3/drivers/google_photo"
|
||||||
|
_ "github.com/alist-org/alist/v3/drivers/ilanzou"
|
||||||
_ "github.com/alist-org/alist/v3/drivers/ipfs_api"
|
_ "github.com/alist-org/alist/v3/drivers/ipfs_api"
|
||||||
_ "github.com/alist-org/alist/v3/drivers/lanzou"
|
_ "github.com/alist-org/alist/v3/drivers/lanzou"
|
||||||
_ "github.com/alist-org/alist/v3/drivers/local"
|
_ "github.com/alist-org/alist/v3/drivers/local"
|
||||||
|
365
drivers/ilanzou/driver.go
Normal file
365
drivers/ilanzou/driver.go
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
package template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alist-org/alist/v3/drivers/base"
|
||||||
|
"github.com/alist-org/alist/v3/internal/driver"
|
||||||
|
"github.com/alist-org/alist/v3/internal/errs"
|
||||||
|
"github.com/alist-org/alist/v3/internal/model"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"github.com/foxxorcat/mopan-sdk-go"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ILanZou struct {
|
||||||
|
model.Storage
|
||||||
|
Addition
|
||||||
|
|
||||||
|
userID string
|
||||||
|
account string
|
||||||
|
upClient *resty.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Config() driver.Config {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) GetAddition() driver.Additional {
|
||||||
|
return &d.Addition
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Init(ctx context.Context) error {
|
||||||
|
d.upClient = base.NewRestyClient().SetTimeout(time.Minute * 10)
|
||||||
|
if d.UUID == "" {
|
||||||
|
res, err := d.unproved("/getUuid", http.MethodGet, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.UUID = utils.Json.Get(res, "uuid").ToString()
|
||||||
|
}
|
||||||
|
res, err := d.proved("/user/account/map", http.MethodGet, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.userID = utils.Json.Get(res, "map", "userId").ToString()
|
||||||
|
d.account = utils.Json.Get(res, "map", "account").ToString()
|
||||||
|
log.Debugf("[ilanzou] init response: %s", res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Drop(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
|
||||||
|
offset := 1
|
||||||
|
limit := 60
|
||||||
|
var res []ListItem
|
||||||
|
for {
|
||||||
|
var resp ListResp
|
||||||
|
_, err := d.proved("/record/file/list", http.MethodGet, func(req *resty.Request) {
|
||||||
|
req.SetQueryParams(map[string]string{
|
||||||
|
"type": "0",
|
||||||
|
"folderId": dir.GetID(),
|
||||||
|
"offset": strconv.Itoa(offset),
|
||||||
|
"limit": strconv.Itoa(limit),
|
||||||
|
}).SetResult(&resp)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, resp.List...)
|
||||||
|
if resp.TotalPage <= resp.Offset {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
return utils.SliceConvert(res, func(f ListItem) (model.Obj, error) {
|
||||||
|
updTime, err := time.ParseInLocation("2006-01-02 15:04:05", f.UpdTime, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
obj := model.Object{
|
||||||
|
ID: strconv.FormatInt(f.FileId, 10),
|
||||||
|
//Path: "",
|
||||||
|
Name: f.FileName,
|
||||||
|
Size: f.FileSize * 1024,
|
||||||
|
Modified: updTime,
|
||||||
|
Ctime: updTime,
|
||||||
|
IsFolder: false,
|
||||||
|
//HashInfo: utils.HashInfo{},
|
||||||
|
}
|
||||||
|
if f.FileType == 2 {
|
||||||
|
obj.IsFolder = true
|
||||||
|
obj.Size = 0
|
||||||
|
obj.ID = strconv.FormatInt(f.FolderId, 10)
|
||||||
|
obj.Name = f.FolderName
|
||||||
|
}
|
||||||
|
return &obj, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
|
||||||
|
u, err := url.Parse("https://api.ilanzou.com/unproved/file/redirect")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query := u.Query()
|
||||||
|
query.Set("uuid", d.UUID)
|
||||||
|
query.Set("devType", "6")
|
||||||
|
query.Set("devCode", d.UUID)
|
||||||
|
query.Set("devModel", "chrome")
|
||||||
|
query.Set("devVersion", "120")
|
||||||
|
query.Set("appVersion", "")
|
||||||
|
ts, err := getTimestamp()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query.Set("timestamp", ts)
|
||||||
|
//query.Set("appToken", d.Token)
|
||||||
|
query.Set("enable", "1")
|
||||||
|
downloadId, err := mopan.AesEncrypt([]byte(fmt.Sprintf("%s|%s", file.GetID(), d.userID)), AesSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query.Set("downloadId", hex.EncodeToString(downloadId))
|
||||||
|
auth, err := mopan.AesEncrypt([]byte(fmt.Sprintf("%s|%d", file.GetID(), time.Now().UnixMilli())), AesSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query.Set("auth", hex.EncodeToString(auth))
|
||||||
|
u.RawQuery = query.Encode()
|
||||||
|
link := model.Link{URL: u.String()}
|
||||||
|
return &link, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
|
||||||
|
res, err := d.proved("/file/folder/save", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"folderDesc": "",
|
||||||
|
"folderId": parentDir.GetID(),
|
||||||
|
"folderName": dirName,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.Object{
|
||||||
|
ID: utils.Json.Get(res, "list", "0", "id").ToString(),
|
||||||
|
//Path: "",
|
||||||
|
Name: dirName,
|
||||||
|
Size: 0,
|
||||||
|
Modified: time.Now(),
|
||||||
|
Ctime: time.Now(),
|
||||||
|
IsFolder: true,
|
||||||
|
//HashInfo: utils.HashInfo{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
||||||
|
var fileIds, folderIds []string
|
||||||
|
if srcObj.IsDir() {
|
||||||
|
folderIds = []string{srcObj.GetID()}
|
||||||
|
} else {
|
||||||
|
fileIds = []string{srcObj.GetID()}
|
||||||
|
}
|
||||||
|
_, err := d.proved("/file/folder/move", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"folderIds": strings.Join(folderIds, ","),
|
||||||
|
"fileIds": strings.Join(fileIds, ","),
|
||||||
|
"targetId": dstDir.GetID(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return srcObj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
|
||||||
|
var err error
|
||||||
|
if srcObj.IsDir() {
|
||||||
|
_, err = d.proved("/file/folder/edit", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"folderDesc": "",
|
||||||
|
"folderId": srcObj.GetID(),
|
||||||
|
"folderName": newName,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
_, err = d.proved("/file/edit", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"fileDesc": "",
|
||||||
|
"fileId": srcObj.GetID(),
|
||||||
|
"fileName": newName,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &model.Object{
|
||||||
|
ID: srcObj.GetID(),
|
||||||
|
//Path: "",
|
||||||
|
Name: newName,
|
||||||
|
Size: srcObj.GetSize(),
|
||||||
|
Modified: time.Now(),
|
||||||
|
Ctime: srcObj.CreateTime(),
|
||||||
|
IsFolder: srcObj.IsDir(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
||||||
|
// TODO copy obj, optional
|
||||||
|
return nil, errs.NotImplement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) Remove(ctx context.Context, obj model.Obj) error {
|
||||||
|
var fileIds, folderIds []string
|
||||||
|
if obj.IsDir() {
|
||||||
|
folderIds = []string{obj.GetID()}
|
||||||
|
} else {
|
||||||
|
fileIds = []string{obj.GetID()}
|
||||||
|
}
|
||||||
|
_, err := d.proved("/file/delete", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"folderIds": strings.Join(folderIds, ","),
|
||||||
|
"fileIds": strings.Join(fileIds, ","),
|
||||||
|
"status": 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefaultPartSize = 1024 * 1024 * 8
|
||||||
|
|
||||||
|
func (d *ILanZou) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||||
|
h := md5.New()
|
||||||
|
// need to calculate md5 of the full content
|
||||||
|
tempFile, err := stream.CacheFullInTempFile()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = tempFile.Close()
|
||||||
|
}()
|
||||||
|
if _, err = io.Copy(h, tempFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
etag := hex.EncodeToString(h.Sum(nil))
|
||||||
|
// get upToken
|
||||||
|
res, err := d.proved("/7n/getUpToken", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"fileId": "",
|
||||||
|
"fileName": stream.GetName(),
|
||||||
|
"fileSize": stream.GetSize() / 1024,
|
||||||
|
"folderId": dstDir.GetID(),
|
||||||
|
"md5": etag,
|
||||||
|
"type": 1,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
upToken := utils.Json.Get(res, "upToken").ToString()
|
||||||
|
now := time.Now()
|
||||||
|
key := fmt.Sprintf("disk/%d/%d/%d/%s/%016d", now.Year(), now.Month(), now.Day(), d.account, now.UnixMilli())
|
||||||
|
var token string
|
||||||
|
if stream.GetSize() > DefaultPartSize {
|
||||||
|
res, err := d.upClient.R().SetMultipartFormData(map[string]string{
|
||||||
|
"token": upToken,
|
||||||
|
"key": key,
|
||||||
|
"fname": stream.GetName(),
|
||||||
|
}).SetMultipartField("file", stream.GetName(), stream.GetMimetype(), tempFile).
|
||||||
|
Post("https://upload.qiniup.com/")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token = utils.Json.Get(res.Body(), "token").ToString()
|
||||||
|
} else {
|
||||||
|
keyBase64 := base64.URLEncoding.EncodeToString([]byte(key))
|
||||||
|
res, err := d.upClient.R().Post(fmt.Sprintf("https://upload.qiniup.com/buckets/wpanstore-lanzou/objects/%s/uploads", keyBase64))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
uploadId := utils.Json.Get(res.Body(), "uploadId").ToString()
|
||||||
|
parts := make([]Part, 0)
|
||||||
|
partNum := (stream.GetSize() + DefaultPartSize - 1) / DefaultPartSize
|
||||||
|
for i := 1; i <= int(partNum); i++ {
|
||||||
|
u := fmt.Sprintf("https://upload.qiniup.com/buckets/wpanstore-lanzou/objects/%s/uploads/%s/%d", keyBase64, uploadId, i)
|
||||||
|
res, err = d.upClient.R().SetBody(io.LimitReader(tempFile, DefaultPartSize)).Put(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
etag := utils.Json.Get(res.Body(), "etag").ToString()
|
||||||
|
parts = append(parts, Part{
|
||||||
|
PartNumber: i,
|
||||||
|
ETag: etag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res, err = d.upClient.R().SetBody(base.Json{
|
||||||
|
"fnmae": stream.GetName(),
|
||||||
|
"parts": parts,
|
||||||
|
}).Post(fmt.Sprintf("https://upload.qiniup.com/buckets/wpanstore-lanzou/objects/%s/uploads/%s", keyBase64, uploadId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token = utils.Json.Get(res.Body(), "token").ToString()
|
||||||
|
}
|
||||||
|
// commit upload
|
||||||
|
var resp UploadResultResp
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
_, err = d.unproved("/7n/results", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetQueryParams(map[string]string{
|
||||||
|
"tokenList": token,
|
||||||
|
"tokenTime": time.Now().Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)"),
|
||||||
|
}).SetResult(&resp)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(resp.List) == 0 {
|
||||||
|
return nil, fmt.Errorf("upload failed, empty response")
|
||||||
|
}
|
||||||
|
if resp.List[0].Status == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
}
|
||||||
|
file := resp.List[0]
|
||||||
|
if file.Status != 1 {
|
||||||
|
return nil, fmt.Errorf("upload failed, status: %d", resp.List[0].Status)
|
||||||
|
}
|
||||||
|
return &model.Object{
|
||||||
|
ID: strconv.FormatInt(file.FileId, 10),
|
||||||
|
//Path: ,
|
||||||
|
Name: file.FileName,
|
||||||
|
Size: stream.GetSize(),
|
||||||
|
Modified: stream.ModTime(),
|
||||||
|
Ctime: stream.CreateTime(),
|
||||||
|
IsFolder: false,
|
||||||
|
HashInfo: utils.NewHashInfo(utils.MD5, etag),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (d *ILanZou) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
|
||||||
|
// return nil, errs.NotSupport
|
||||||
|
//}
|
||||||
|
|
||||||
|
var _ driver.Driver = (*ILanZou)(nil)
|
35
drivers/ilanzou/meta.go
Normal file
35
drivers/ilanzou/meta.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alist-org/alist/v3/internal/driver"
|
||||||
|
"github.com/alist-org/alist/v3/internal/op"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Addition struct {
|
||||||
|
driver.RootID
|
||||||
|
Username string `json:"username" type:"string" required:"true"`
|
||||||
|
Password string `json:"password" type:"string" required:"true"`
|
||||||
|
|
||||||
|
Token string
|
||||||
|
UUID string
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = driver.Config{
|
||||||
|
Name: "ILanZou",
|
||||||
|
LocalSort: false,
|
||||||
|
OnlyLocal: false,
|
||||||
|
OnlyProxy: false,
|
||||||
|
NoCache: false,
|
||||||
|
NoUpload: false,
|
||||||
|
NeedMs: false,
|
||||||
|
DefaultRoot: "0",
|
||||||
|
CheckStatus: false,
|
||||||
|
Alert: "",
|
||||||
|
NoOverwriteUpload: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
op.RegisterDriver(func() driver.Driver {
|
||||||
|
return &ILanZou{}
|
||||||
|
})
|
||||||
|
}
|
57
drivers/ilanzou/types.go
Normal file
57
drivers/ilanzou/types.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package template
|
||||||
|
|
||||||
|
type ListResp struct {
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Offset int `json:"offset"`
|
||||||
|
TotalPage int `json:"totalPage"`
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
List []ListItem `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListItem struct {
|
||||||
|
IconId int `json:"iconId"`
|
||||||
|
IsAmt int `json:"isAmt"`
|
||||||
|
FolderDesc string `json:"folderDesc,omitempty"`
|
||||||
|
AddTime string `json:"addTime"`
|
||||||
|
FolderId int64 `json:"folderId"`
|
||||||
|
ParentId int64 `json:"parentId"`
|
||||||
|
ParentName string `json:"parentName"`
|
||||||
|
NoteType int `json:"noteType,omitempty"`
|
||||||
|
UpdTime string `json:"updTime"`
|
||||||
|
IsShare int `json:"isShare"`
|
||||||
|
FolderIcon string `json:"folderIcon,omitempty"`
|
||||||
|
FolderName string `json:"folderName,omitempty"`
|
||||||
|
FileType int `json:"fileType"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
IsFileShare int `json:"isFileShare,omitempty"`
|
||||||
|
FileName string `json:"fileName,omitempty"`
|
||||||
|
FileStars float64 `json:"fileStars,omitempty"`
|
||||||
|
IsFileDownload int `json:"isFileDownload,omitempty"`
|
||||||
|
FileComments int `json:"fileComments,omitempty"`
|
||||||
|
FileSize int64 `json:"fileSize,omitempty"`
|
||||||
|
FileIcon string `json:"fileIcon,omitempty"`
|
||||||
|
FileDownloads int `json:"fileDownloads,omitempty"`
|
||||||
|
FileUrl interface{} `json:"fileUrl"`
|
||||||
|
FileLikes int `json:"fileLikes,omitempty"`
|
||||||
|
FileId int64 `json:"fileId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Part struct {
|
||||||
|
PartNumber int `json:"partNumber"`
|
||||||
|
ETag string `json:"etag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadResultResp struct {
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
List []struct {
|
||||||
|
FileIconId int `json:"fileIconId"`
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
FileIcon string `json:"fileIcon"`
|
||||||
|
FileId int64 `json:"fileId"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
} `json:"list"`
|
||||||
|
}
|
105
drivers/ilanzou/util.go
Normal file
105
drivers/ilanzou/util.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package template
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/alist-org/alist/v3/drivers/base"
|
||||||
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
|
"github.com/foxxorcat/mopan-sdk-go"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Base = "https://api.ilanzou.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
AesSecret = []byte("lanZouY-disk-app")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *ILanZou) login() error {
|
||||||
|
res, err := d.unproved("/login", http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(base.Json{
|
||||||
|
"loginName": d.Username,
|
||||||
|
"loginPwd": d.Password,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.Token = utils.Json.Get(res, "data", "appToken").ToString()
|
||||||
|
if d.Token == "" {
|
||||||
|
return fmt.Errorf("failed to login: token is empty, resp: %s", res)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimestamp() (string, error) {
|
||||||
|
ts := time.Now().UnixMilli()
|
||||||
|
tsStr := strconv.FormatInt(ts, 10)
|
||||||
|
res, err := mopan.AesEncrypt([]byte(tsStr), AesSecret)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) request(pathname, method string, callback base.ReqCallback, proved bool, retry ...bool) ([]byte, error) {
|
||||||
|
req := base.RestyClient.R()
|
||||||
|
ts, err := getTimestamp()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.SetQueryParams(map[string]string{
|
||||||
|
"uuid": d.UUID,
|
||||||
|
"devType": "6",
|
||||||
|
"devCode": d.UUID,
|
||||||
|
"devModel": "chrome",
|
||||||
|
"devVersion": "120",
|
||||||
|
"appVersion": "",
|
||||||
|
"timestamp": ts,
|
||||||
|
//"appToken": d.Token,
|
||||||
|
"extra": "2",
|
||||||
|
})
|
||||||
|
if proved {
|
||||||
|
req.SetQueryParam("appToken", d.Token)
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
callback(req)
|
||||||
|
}
|
||||||
|
res, err := req.Execute(method, Base+pathname)
|
||||||
|
if err != nil {
|
||||||
|
if res != nil {
|
||||||
|
log.Errorf("[iLanZou] request error: %s", res.String())
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
isRetry := len(retry) > 0 && retry[0]
|
||||||
|
body := res.Body()
|
||||||
|
code := utils.Json.Get(body, "code").ToInt()
|
||||||
|
msg := utils.Json.Get(body, "msg").ToString()
|
||||||
|
if code != 200 {
|
||||||
|
if !isRetry && proved && (utils.SliceContains([]int{-1, -2}, code) || d.Token == "") {
|
||||||
|
err = d.login()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.request(pathname, method, callback, proved, true)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%d: %s", code, msg)
|
||||||
|
}
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) unproved(pathname, method string, callback base.ReqCallback) ([]byte, error) {
|
||||||
|
return d.request("/unproved"+pathname, method, callback, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ILanZou) proved(pathname, method string, callback base.ReqCallback) ([]byte, error) {
|
||||||
|
return d.request("/proved"+pathname, method, callback, true)
|
||||||
|
}
|
@ -100,27 +100,35 @@ func (d *Vtencent) LoadUser() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Vtencent) GetFiles(dirId string) ([]File, error) {
|
func (d *Vtencent) GetFiles(dirId string) ([]File, error) {
|
||||||
api := "https://api.vs.tencent.com/PaaS/Material/SearchResource"
|
var res []File
|
||||||
form := fmt.Sprintf(`{
|
//offset := 0
|
||||||
|
for {
|
||||||
|
api := "https://api.vs.tencent.com/PaaS/Material/SearchResource"
|
||||||
|
form := fmt.Sprintf(`{
|
||||||
"Text":"",
|
"Text":"",
|
||||||
"Text":"",
|
"Text":"",
|
||||||
"Offset":0,
|
"Offset":%d,
|
||||||
"Limit":20000,
|
"Limit":50,
|
||||||
"Sort":{"Field":"%s","Order":"%s"},
|
"Sort":{"Field":"%s","Order":"%s"},
|
||||||
"CreateTimeRanges":[],
|
"CreateTimeRanges":[],
|
||||||
"MaterialTypes":[],
|
"MaterialTypes":[],
|
||||||
"ReviewStatuses":[],
|
"ReviewStatuses":[],
|
||||||
"Tags":[],
|
"Tags":[],
|
||||||
"SearchScopes":[{"Owner":{"Type":"PERSON","Id":"%s"},"ClassId":%s,"SearchOneDepth":true}]
|
"SearchScopes":[{"Owner":{"Type":"PERSON","Id":"%s"},"ClassId":%s,"SearchOneDepth":true}]
|
||||||
}`, d.Addition.OrderBy, d.Addition.OrderDirection, d.TfUid, dirId)
|
}`, len(res), d.Addition.OrderBy, d.Addition.OrderDirection, d.TfUid, dirId)
|
||||||
var resps RspFiles
|
var resp RspFiles
|
||||||
_, err := d.request(api, http.MethodPost, func(req *resty.Request) {
|
_, err := d.request(api, http.MethodPost, func(req *resty.Request) {
|
||||||
req.SetBody(form).ForceContentType("application/json")
|
req.SetBody(form).ForceContentType("application/json")
|
||||||
}, &resps)
|
}, &resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []File{}, err
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, resp.Data.ResourceInfoSet...)
|
||||||
|
if len(resp.Data.ResourceInfoSet) <= 0 || len(res) >= resp.Data.TotalCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return resps.Data.ResourceInfoSet, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Vtencent) CreateUploadMaterial(classId int, fileName string, UploadSummaryKey string) (RspCreatrMaterial, error) {
|
func (d *Vtencent) CreateUploadMaterial(classId int, fileName string, UploadSummaryKey string) (RspCreatrMaterial, error) {
|
||||||
|
@ -4,4 +4,8 @@ chown -R ${PUID}:${PGID} /opt/alist/
|
|||||||
|
|
||||||
umask ${UMASK}
|
umask ${UMASK}
|
||||||
|
|
||||||
exec su-exec ${PUID}:${PGID} ./alist server --no-prefix
|
if [ "$1" = "version" ]; then
|
||||||
|
./alist version
|
||||||
|
else
|
||||||
|
exec su-exec ${PUID}:${PGID} ./alist server --no-prefix
|
||||||
|
fi
|
6
go.mod
6
go.mod
@ -9,7 +9,7 @@ require (
|
|||||||
github.com/Xhofe/wopan-sdk-go v0.1.2
|
github.com/Xhofe/wopan-sdk-go v0.1.2
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible
|
github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible
|
||||||
github.com/avast/retry-go v3.0.0+incompatible
|
github.com/avast/retry-go v3.0.0+incompatible
|
||||||
github.com/aws/aws-sdk-go v1.49.13
|
github.com/aws/aws-sdk-go v1.49.15
|
||||||
github.com/blevesearch/bleve/v2 v2.3.10
|
github.com/blevesearch/bleve/v2 v2.3.10
|
||||||
github.com/caarlos0/env/v9 v9.0.0
|
github.com/caarlos0/env/v9 v9.0.0
|
||||||
github.com/charmbracelet/bubbles v0.17.1
|
github.com/charmbracelet/bubbles v0.17.1
|
||||||
@ -51,8 +51,8 @@ require (
|
|||||||
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
github.com/winfsp/cgofuse v1.5.1-0.20230130140708-f87f5db493b5
|
||||||
github.com/xhofe/tache v0.1.1
|
github.com/xhofe/tache v0.1.1
|
||||||
golang.org/x/crypto v0.17.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b
|
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc
|
||||||
golang.org/x/image v0.14.0
|
golang.org/x/image v0.15.0
|
||||||
golang.org/x/net v0.19.0
|
golang.org/x/net v0.19.0
|
||||||
golang.org/x/oauth2 v0.15.0
|
golang.org/x/oauth2 v0.15.0
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
|
6
go.sum
6
go.sum
@ -36,6 +36,8 @@ github.com/aws/aws-sdk-go v1.46.7 h1:IjvAWeiJZlbETOemOwvheN5L17CvKvKW0T1xOC6d3Sc
|
|||||||
github.com/aws/aws-sdk-go v1.46.7/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.46.7/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
github.com/aws/aws-sdk-go v1.49.13 h1:f4mGztsgnx2dR9r8FQYa9YW/RsKb+N7bgef4UGrOW1Y=
|
github.com/aws/aws-sdk-go v1.49.13 h1:f4mGztsgnx2dR9r8FQYa9YW/RsKb+N7bgef4UGrOW1Y=
|
||||||
github.com/aws/aws-sdk-go v1.49.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
github.com/aws/aws-sdk-go v1.49.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||||
|
github.com/aws/aws-sdk-go v1.49.15 h1:aH9bSV4kL4ziH0AMtuYbukGIVebXddXBL0cKZ1zj15k=
|
||||||
|
github.com/aws/aws-sdk-go v1.49.15/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
@ -527,11 +529,15 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM
|
|||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
|
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
|
||||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
|
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
||||||
|
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
|
||||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
||||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
||||||
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
|
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||||
|
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -449,16 +449,20 @@ type Buf struct {
|
|||||||
size int //expected size
|
size int //expected size
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
off int
|
off int
|
||||||
rw sync.RWMutex
|
rw sync.Mutex
|
||||||
notify chan struct{}
|
//notify chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuf is a buffer that can have 1 read & 1 write at the same time.
|
// NewBuf is a buffer that can have 1 read & 1 write at the same time.
|
||||||
// when read is faster write, immediately feed data to read after written
|
// when read is faster write, immediately feed data to read after written
|
||||||
func NewBuf(ctx context.Context, maxSize int, id int) *Buf {
|
func NewBuf(ctx context.Context, maxSize int, id int) *Buf {
|
||||||
d := make([]byte, 0, maxSize)
|
d := make([]byte, 0, maxSize)
|
||||||
return &Buf{ctx: ctx, buffer: bytes.NewBuffer(d), size: maxSize, notify: make(chan struct{})}
|
return &Buf{
|
||||||
|
ctx: ctx,
|
||||||
|
buffer: bytes.NewBuffer(d),
|
||||||
|
size: maxSize,
|
||||||
|
//notify: make(chan struct{}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
func (br *Buf) Reset(size int) {
|
func (br *Buf) Reset(size int) {
|
||||||
br.buffer.Reset()
|
br.buffer.Reset()
|
||||||
@ -476,9 +480,9 @@ func (br *Buf) Read(p []byte) (n int, err error) {
|
|||||||
if br.off >= br.size {
|
if br.off >= br.size {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
br.rw.RLock()
|
br.rw.Lock()
|
||||||
n, err = br.buffer.Read(p)
|
n, err = br.buffer.Read(p)
|
||||||
br.rw.RUnlock()
|
br.rw.Unlock()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
br.off += n
|
br.off += n
|
||||||
return n, err
|
return n, err
|
||||||
@ -495,8 +499,8 @@ func (br *Buf) Read(p []byte) (n int, err error) {
|
|||||||
select {
|
select {
|
||||||
case <-br.ctx.Done():
|
case <-br.ctx.Done():
|
||||||
return 0, br.ctx.Err()
|
return 0, br.ctx.Err()
|
||||||
case <-br.notify:
|
//case <-br.notify:
|
||||||
return 0, nil
|
// return 0, nil
|
||||||
case <-time.After(time.Millisecond * 200):
|
case <-time.After(time.Millisecond * 200):
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
@ -510,12 +514,12 @@ func (br *Buf) Write(p []byte) (n int, err error) {
|
|||||||
defer br.rw.Unlock()
|
defer br.rw.Unlock()
|
||||||
n, err = br.buffer.Write(p)
|
n, err = br.buffer.Write(p)
|
||||||
select {
|
select {
|
||||||
case br.notify <- struct{}{}:
|
//case br.notify <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *Buf) Close() {
|
func (br *Buf) Close() {
|
||||||
close(br.notify)
|
//close(br.notify)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user