mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-11-25 19:37:41 +08:00
feat(offline_download): add 123 open (#1427)
This commit is contained in:
@@ -229,6 +229,14 @@ func (d *Open123) GetDetails(ctx context.Context) (*model.StorageDetails, error)
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Open123) OfflineDownload(ctx context.Context, url string, dir model.Obj, callback string) (int, error) {
|
||||||
|
return d.createOfflineDownloadTask(ctx, url, dir.GetID(), callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Open123) OfflineDownloadProcess(ctx context.Context, taskID int) (float64, int, error) {
|
||||||
|
return d.queryOfflineDownloadStatus(ctx, taskID)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ driver.Driver = (*Open123)(nil)
|
_ driver.Driver = (*Open123)(nil)
|
||||||
_ driver.PutResult = (*Open123)(nil)
|
_ driver.PutResult = (*Open123)(nil)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ func (a *ApiInfo) Require() {
|
|||||||
a.token <- struct{}{}
|
a.token <- struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ApiInfo) Release() {
|
func (a *ApiInfo) Release() {
|
||||||
if a.qps > 0 {
|
if a.qps > 0 {
|
||||||
time.AfterFunc(time.Second, func() {
|
time.AfterFunc(time.Second, func() {
|
||||||
@@ -26,13 +27,16 @@ func (a *ApiInfo) Release() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ApiInfo) SetQPS(qps int) {
|
func (a *ApiInfo) SetQPS(qps int) {
|
||||||
a.qps = qps
|
a.qps = qps
|
||||||
a.token = make(chan struct{}, qps)
|
a.token = make(chan struct{}, qps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ApiInfo) NowLen() int {
|
func (a *ApiInfo) NowLen() int {
|
||||||
return len(a.token)
|
return len(a.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitApiInfo(url string, qps int) *ApiInfo {
|
func InitApiInfo(url string, qps int) *ApiInfo {
|
||||||
return &ApiInfo{
|
return &ApiInfo{
|
||||||
url: url,
|
url: url,
|
||||||
@@ -185,3 +189,18 @@ type UploadCompleteResp struct {
|
|||||||
FileID int64 `json:"fileID"`
|
FileID int64 `json:"fileID"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OfflineDownloadResp struct {
|
||||||
|
BaseResp
|
||||||
|
Data struct {
|
||||||
|
TaskID int `json:"taskID"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OfflineDownloadProcessResp struct {
|
||||||
|
BaseResp
|
||||||
|
Data struct {
|
||||||
|
Process float64 `json:"process"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ var ( // 不同情况下获取的AccessTokenQPS限制不同 如下模块化易
|
|||||||
Trash = InitApiInfo(Api+"/api/v1/file/trash", 2)
|
Trash = InitApiInfo(Api+"/api/v1/file/trash", 2)
|
||||||
UploadCreate = InitApiInfo(Api+"/upload/v2/file/create", 2)
|
UploadCreate = InitApiInfo(Api+"/upload/v2/file/create", 2)
|
||||||
UploadComplete = InitApiInfo(Api+"/upload/v2/file/upload_complete", 0)
|
UploadComplete = InitApiInfo(Api+"/upload/v2/file/upload_complete", 0)
|
||||||
|
|
||||||
|
OfflineDownload = InitApiInfo(Api+"/api/v1/offline/download", 1)
|
||||||
|
OfflineDownloadProcess = InitApiInfo(Api+"/api/v1/offline/download/process", 5)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *Open123) Request(apiInfo *ApiInfo, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
func (d *Open123) Request(apiInfo *ApiInfo, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||||
@@ -277,3 +280,34 @@ func (d *Open123) trash(fileId int64) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Open123) createOfflineDownloadTask(ctx context.Context, url string, dirID, callback string) (taskID int, err error) {
|
||||||
|
body := base.Json{
|
||||||
|
"url": url,
|
||||||
|
"dirID": dirID,
|
||||||
|
}
|
||||||
|
if len(callback) > 0 {
|
||||||
|
body["callBackUrl"] = callback
|
||||||
|
}
|
||||||
|
var resp OfflineDownloadResp
|
||||||
|
_, err = d.Request(OfflineDownload, http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetBody(body)
|
||||||
|
}, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return resp.Data.TaskID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Open123) queryOfflineDownloadStatus(ctx context.Context, taskID int) (process float64, status int, err error) {
|
||||||
|
var resp OfflineDownloadProcessResp
|
||||||
|
_, err = d.Request(OfflineDownloadProcess, http.MethodGet, func(req *resty.Request) {
|
||||||
|
req.SetQueryParams(map[string]string{
|
||||||
|
"taskID": strconv.Itoa(taskID),
|
||||||
|
})
|
||||||
|
}, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return .0, 0, err
|
||||||
|
}
|
||||||
|
return resp.Data.Process, resp.Data.Status, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ const (
|
|||||||
QbittorrentUrl = "qbittorrent_url"
|
QbittorrentUrl = "qbittorrent_url"
|
||||||
QbittorrentSeedtime = "qbittorrent_seedtime"
|
QbittorrentSeedtime = "qbittorrent_seedtime"
|
||||||
|
|
||||||
|
// 123 open offline download
|
||||||
|
Pan123OpenOfflineDownloadCallbackUrl = "123_open_callback_url"
|
||||||
|
Pan123OpenTempDir = "123_open_temp_dir"
|
||||||
|
|
||||||
// ftp
|
// ftp
|
||||||
FTPPublicHost = "ftp_public_host"
|
FTPPublicHost = "ftp_public_host"
|
||||||
FTPPasvPortMap = "ftp_pasv_port_map"
|
FTPPasvPortMap = "ftp_pasv_port_map"
|
||||||
|
|||||||
119
internal/offline_download/123_open/client.go
Normal file
119
internal/offline_download/123_open/client.go
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
package _123_open
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/offline_download/tool"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/internal/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Open123 struct{}
|
||||||
|
|
||||||
|
func (*Open123) Name() string {
|
||||||
|
return "123 Open"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) Items() []model.SettingItem {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) Run(_ *tool.DownloadTask) error {
|
||||||
|
return errs.NotSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) Init() (string, error) {
|
||||||
|
return "ok", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) IsReady() bool {
|
||||||
|
tempDir := setting.GetStr(conf.Pan123OpenTempDir)
|
||||||
|
if tempDir == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
storage, _, err := op.GetStorageAndActualPath(tempDir)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, ok := storage.(*_123_open.Open123); !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) AddURL(args *tool.AddUrlArgs) (string, error) {
|
||||||
|
storage, actualPath, err := op.GetStorageAndActualPath(args.TempDir)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
driver123Open, ok := storage.(*_123_open.Open123)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
if err := op.MakeDir(ctx, storage, actualPath); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
parentDir, err := op.GetUnwrap(ctx, storage, actualPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
cb := setting.GetStr(conf.Pan123OpenOfflineDownloadCallbackUrl)
|
||||||
|
taskID, err := driver123Open.OfflineDownload(ctx, args.Url, parentDir, cb)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to add offline download task: %w", err)
|
||||||
|
}
|
||||||
|
return strconv.Itoa(taskID), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) Remove(_ *tool.DownloadTask) error {
|
||||||
|
return errs.NotSupport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Open123) Status(task *tool.DownloadTask) (*tool.Status, error) {
|
||||||
|
taskID, err := strconv.Atoi(task.GID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse task ID: %s", task.GID)
|
||||||
|
}
|
||||||
|
storage, _, err := op.GetStorageAndActualPath(task.TempDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
driver123Open, ok := storage.(*_123_open.Open123)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported storage driver for offline download, only 123 Open is supported")
|
||||||
|
}
|
||||||
|
process, status, err := driver123Open.OfflineDownloadProcess(context.Background(), taskID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var statusStr string
|
||||||
|
switch status {
|
||||||
|
case 0:
|
||||||
|
statusStr = "downloading"
|
||||||
|
case 1:
|
||||||
|
err = fmt.Errorf("offline download failed")
|
||||||
|
case 2:
|
||||||
|
statusStr = "succeed"
|
||||||
|
case 3:
|
||||||
|
statusStr = "retrying"
|
||||||
|
}
|
||||||
|
return &tool.Status{
|
||||||
|
Progress: process,
|
||||||
|
Completed: status == 2,
|
||||||
|
Status: statusStr,
|
||||||
|
Err: err,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tool.Tool = (*Open123)(nil)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tool.Tools.Add(&Open123{})
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package offline_download
|
|||||||
import (
|
import (
|
||||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115"
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115"
|
||||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115_open"
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/115_open"
|
||||||
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/123_open"
|
||||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/aria2"
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/aria2"
|
||||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/http"
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/http"
|
||||||
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/pikpak"
|
_ "github.com/OpenListTeam/OpenList/v4/internal/offline_download/pikpak"
|
||||||
|
|||||||
@@ -2,18 +2,16 @@ package tool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
|
||||||
|
|
||||||
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/server/common"
|
|
||||||
|
|
||||||
"net/url"
|
"net/url"
|
||||||
stdpath "path"
|
stdpath "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
||||||
|
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
||||||
|
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunderx"
|
"github.com/OpenListTeam/OpenList/v4/drivers/thunderx"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||||
@@ -22,6 +20,7 @@ import (
|
|||||||
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
"github.com/OpenListTeam/OpenList/v4/internal/op"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/setting"
|
"github.com/OpenListTeam/OpenList/v4/internal/setting"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/task"
|
"github.com/OpenListTeam/OpenList/v4/internal/task"
|
||||||
|
"github.com/OpenListTeam/OpenList/v4/server/common"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -104,6 +103,13 @@ func AddURL(ctx context.Context, args *AddURLArgs) (task.TaskExtensionInfo, erro
|
|||||||
} else {
|
} else {
|
||||||
tempDir = filepath.Join(setting.GetStr(conf.Pan115OpenTempDir), uid)
|
tempDir = filepath.Join(setting.GetStr(conf.Pan115OpenTempDir), uid)
|
||||||
}
|
}
|
||||||
|
case "123 Open":
|
||||||
|
if _, ok := storage.(*_123_open.Open123); ok && dstDirActualPath != "/" {
|
||||||
|
// directly offline downloading to the root path is not allowed via 123 open platform
|
||||||
|
tempDir = args.DstDirPath
|
||||||
|
} else {
|
||||||
|
tempDir = filepath.Join(setting.GetStr(conf.Pan123OpenTempDir), uid)
|
||||||
|
}
|
||||||
case "PikPak":
|
case "PikPak":
|
||||||
if _, ok := storage.(*pikpak.PikPak); ok {
|
if _, ok := storage.(*pikpak.PikPak); ok {
|
||||||
tempDir = args.DstDirPath
|
tempDir = args.DstDirPath
|
||||||
|
|||||||
@@ -111,6 +111,9 @@ outer:
|
|||||||
if t.tool.Name() == "115 Open" {
|
if t.tool.Name() == "115 Open" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if t.tool.Name() == "123 Open" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
t.Status = "offline download completed, maybe transferring"
|
t.Status = "offline download completed, maybe transferring"
|
||||||
// hack for qBittorrent
|
// hack for qBittorrent
|
||||||
if t.tool.Name() == "qBittorrent" {
|
if t.tool.Name() == "qBittorrent" {
|
||||||
@@ -174,7 +177,7 @@ func (t *DownloadTask) Update() (bool, error) {
|
|||||||
|
|
||||||
func (t *DownloadTask) Transfer() error {
|
func (t *DownloadTask) Transfer() error {
|
||||||
toolName := t.tool.Name()
|
toolName := t.tool.Name()
|
||||||
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
|
if toolName == "115 Cloud" || toolName == "115 Open" || toolName == "123 Open" || toolName == "PikPak" || toolName == "Thunder" || toolName == "ThunderX" || toolName == "ThunderBrowser" {
|
||||||
// 如果不是直接下载到目标路径,则进行转存
|
// 如果不是直接下载到目标路径,则进行转存
|
||||||
if t.TempDir != t.DstDirPath {
|
if t.TempDir != t.DstDirPath {
|
||||||
return transferObj(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)
|
return transferObj(t.Ctx(), t.TempDir, t.DstDirPath, t.DeletePolicy)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
_115 "github.com/OpenListTeam/OpenList/v4/drivers/115"
|
||||||
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
_115_open "github.com/OpenListTeam/OpenList/v4/drivers/115_open"
|
||||||
|
_123_open "github.com/OpenListTeam/OpenList/v4/drivers/123_open"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
"github.com/OpenListTeam/OpenList/v4/drivers/pikpak"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
"github.com/OpenListTeam/OpenList/v4/drivers/thunder"
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
"github.com/OpenListTeam/OpenList/v4/drivers/thunder_browser"
|
||||||
@@ -200,6 +201,52 @@ func Set115Open(c *gin.Context) {
|
|||||||
common.SuccessResp(c, "ok")
|
common.SuccessResp(c, "ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Set123OpenReq struct {
|
||||||
|
TempDir string `json:"temp_dir" form:"temp_dir"`
|
||||||
|
CallbackUrl string `json:"callback_url" form:"callback_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Set123Open(c *gin.Context) {
|
||||||
|
var req Set123OpenReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.TempDir != "" {
|
||||||
|
storage, _, err := op.GetStorageAndActualPath(req.TempDir)
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorStrResp(c, "storage does not exists", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK {
|
||||||
|
common.ErrorStrResp(c, "storage not init: "+storage.GetStorage().Status, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := storage.(*_123_open.Open123); !ok {
|
||||||
|
common.ErrorStrResp(c, "unsupported storage driver for offline download, only 123 Open is supported", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items := []model.SettingItem{
|
||||||
|
{Key: conf.Pan123OpenTempDir, Value: req.TempDir, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
|
||||||
|
{Key: conf.Pan123OpenOfflineDownloadCallbackUrl, Value: req.CallbackUrl, Type: conf.TypeString, Group: model.OFFLINE_DOWNLOAD, Flag: model.PRIVATE},
|
||||||
|
}
|
||||||
|
if err := op.SaveSettingItems(items); err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_tool, err := tool.Tools.Get("123 Open")
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := _tool.Init(); err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.SuccessResp(c, "ok")
|
||||||
|
}
|
||||||
|
|
||||||
type SetPikPakReq struct {
|
type SetPikPakReq struct {
|
||||||
TempDir string `json:"temp_dir" form:"temp_dir"`
|
TempDir string `json:"temp_dir" form:"temp_dir"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ func admin(g *gin.RouterGroup) {
|
|||||||
setting.POST("/set_transmission", handles.SetTransmission)
|
setting.POST("/set_transmission", handles.SetTransmission)
|
||||||
setting.POST("/set_115", handles.Set115)
|
setting.POST("/set_115", handles.Set115)
|
||||||
setting.POST("/set_115_open", handles.Set115Open)
|
setting.POST("/set_115_open", handles.Set115Open)
|
||||||
|
setting.POST("/set_123_open", handles.Set123Open)
|
||||||
setting.POST("/set_pikpak", handles.SetPikPak)
|
setting.POST("/set_pikpak", handles.SetPikPak)
|
||||||
setting.POST("/set_thunder", handles.SetThunder)
|
setting.POST("/set_thunder", handles.SetThunder)
|
||||||
setting.POST("/set_thunderx", handles.SetThunderX)
|
setting.POST("/set_thunderx", handles.SetThunderX)
|
||||||
|
|||||||
Reference in New Issue
Block a user