From 75c5bd14c14bffa794e84cf56804e7c600282da2 Mon Sep 17 00:00:00 2001
From: chalkim
Date: Wed, 15 Jan 2025 09:59:41 +0800
Subject: [PATCH] feature: support cloudflare r2
---
frontend/src/api/torrent.ts | 2 +
frontend/src/components/prompts/Torrent.vue | 9 +++
frontend/src/i18n/zh-cn.json | 13 +++-
frontend/src/types/settings.d.ts | 5 ++
frontend/src/views/files/FileListing.vue | 13 ++++
frontend/src/views/settings/Global.vue | 61 ++++++++++++++++
go.mod | 19 +++++
go.sum | 40 +++++++++++
http/settings.go | 2 +
http/torrent.go | 3 +-
settings/torrent.go | 13 ++--
torrent/r2_client.go | 80 +++++++++++++++++++++
torrent/torrent.go | 35 ++++++++-
users/torrent.go | 1 +
14 files changed, 286 insertions(+), 10 deletions(-)
create mode 100644 torrent/r2_client.go
diff --git a/frontend/src/api/torrent.ts b/frontend/src/api/torrent.ts
index 16cecf9d..e47e5625 100644
--- a/frontend/src/api/torrent.ts
+++ b/frontend/src/api/torrent.ts
@@ -13,6 +13,7 @@ export async function makeTorrent(
name: string,
pieceLen: number,
privateFlag: boolean,
+ r2Flag: boolean,
source: string,
webSeeds: string[]
) {
@@ -29,6 +30,7 @@ export async function makeTorrent(
name: name,
pieceLen: pieceLen,
private: privateFlag,
+ r2: r2Flag,
source: source,
webSeeds: webSeeds,
});
diff --git a/frontend/src/components/prompts/Torrent.vue b/frontend/src/components/prompts/Torrent.vue
index 2ed3a0b7..337db9e5 100644
--- a/frontend/src/components/prompts/Torrent.vue
+++ b/frontend/src/components/prompts/Torrent.vue
@@ -81,6 +81,11 @@
{{ $t("prompts.privateTorrent") }}
+
+
+
+ {{ $t("prompts.r2") }}
+
@@ -113,6 +118,7 @@ export default {
name: "",
pieceLen: 0,
privateFlag: false,
+ r2Flag: false,
source: "",
webSeeds: [],
detailedView: false
@@ -148,6 +154,7 @@ export default {
this.name = res.name;
this.pieceLen = res.pieceLen;
this.privateFlag = res.private;
+ this.r2Flag = res.r2Flag;
this.source = res.source;
this.webSeeds = res.webSeeds.join("\n");
});
@@ -175,6 +182,7 @@ export default {
this.name,
parseInt(this.pieceLen),
this.privateFlag,
+ this.r2Flag,
this.source,
this.webSeeds.split("\n").map((t) => t.trim()).filter((t) => t),
).then(
@@ -198,6 +206,7 @@ export default {
this.date = true;
this.pieceLen = 18;
this.privateFlag = false;
+ this.r2Flag=false;
this.source = "";
this.webSeeds = [];
} catch (e) {
diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json
index 92a7dcab..e30cd919 100644
--- a/frontend/src/i18n/zh-cn.json
+++ b/frontend/src/i18n/zh-cn.json
@@ -154,7 +154,8 @@
"source": "源:",
"includeDate": "写入创建日期",
"privateTorrent": "私有 torrent (不会在DHT网络上分发)",
- "publishMessage": "你确定要发布这个种子吗?"
+ "publishMessage": "你确定要发布这个种子吗?",
+ "r2": "上传到 Cloudflare R2 进行辅种"
},
"search": {
"images": "图像",
@@ -260,7 +261,15 @@
"qbSettingsDescription": "你可以在此设置 qBittorrent WebUI 的地址、用户名和密码。",
"qbUrl": "qBittorrent WebUI 地址",
"qbUsername": "qBittorrent WebUI 用户名",
- "qbPassword": "qBittorrent WebUI 密码"
+ "qbPassword": "qBittorrent WebUI 密码",
+ "r2": "辅种 (Cloudflare R2)",
+ "r2Description": "你可以在此设置 Cloudflare R2 的API密钥。",
+ "accountKeySecretHidden": "API 密钥已隐藏",
+ "accountId": "账户 ID",
+ "accountKeyId": "访问密钥 ID",
+ "accountKeySecret": "机密访问密钥",
+ "bucket": "存储桶名称",
+ "domain": "公开访问域"
},
"sidebar": {
"help": "帮助",
diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts
index ae989e40..ab00d456 100644
--- a/frontend/src/types/settings.d.ts
+++ b/frontend/src/types/settings.d.ts
@@ -55,6 +55,11 @@ interface SettingsTorrent {
qbUrl?: string;
qbUsername?: string;
qbPassword?: string;
+ accountId?: string;
+ accountKeyId?: string;
+ accountKeySecret?: string;
+ bucket?: string;
+ domain?: string;
}
interface SettingsUnit {
diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue
index 9ced6f0b..e5825477 100644
--- a/frontend/src/views/files/FileListing.vue
+++ b/frontend/src/views/files/FileListing.vue
@@ -99,6 +99,19 @@
{{ fileStore.selectedCount }} selected
+
+
+
+
+ {{ t("settings.r2") }}
+ {{ t("settings.r2Description") }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -384,6 +437,14 @@ const save = async () => {
}
newSettings.shell = shellValue.value.split("\n");
+ // remove qbPassword & accountKeySecret if empty
+ if (newSettings.torrent.qbPassword === "") {
+ delete newSettings.torrent.qbPassword;
+ }
+ if (newSettings.torrent.accountKeySecret === "") {
+ delete newSettings.torrent.accountKeySecret;
+ }
+
if (newSettings.branding.theme !== getTheme()) {
setTheme(newSettings.branding.theme);
}
diff --git a/go.mod b/go.mod
index 7f5b9b3e..0d562397 100644
--- a/go.mod
+++ b/go.mod
@@ -54,6 +54,24 @@ require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/asticode/go-astikit v0.42.0 // indirect
github.com/asticode/go-astits v1.13.0 // indirect
+ github.com/aws/aws-sdk-go-v2 v1.32.8 // indirect
+ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.28.10 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.51 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.8 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.8 // indirect
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.72.2 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 // indirect
+ github.com/aws/smithy-go v1.22.1 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/benbjohnson/immutable v0.3.0 // indirect
github.com/bits-and-blooms/bitset v1.2.2 // indirect
@@ -79,6 +97,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
diff --git a/go.sum b/go.sum
index c17e2a97..07e2a29a 100644
--- a/go.sum
+++ b/go.sum
@@ -92,6 +92,42 @@ github.com/asticode/go-astisub v0.26.2/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2z
github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
github.com/asticode/go-astits v1.13.0 h1:XOgkaadfZODnyZRR5Y0/DWkA9vrkLLPLeeOvDwfKZ1c=
github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
+github.com/aws/aws-sdk-go-v2 v1.32.8 h1:cZV+NUS/eGxKXMtmyhtYPJ7Z4YLoI/V8bkTdRZfYhGo=
+github.com/aws/aws-sdk-go-v2 v1.32.8/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
+github.com/aws/aws-sdk-go-v2/config v1.28.10 h1:fKODZHfqQu06pCzR69KJ3GuttraRJkhlC8g80RZ0Dfg=
+github.com/aws/aws-sdk-go-v2/config v1.28.10/go.mod h1:PvdxRYZ5Um9QMq9PQ0zHHNdtKK+he2NHtFCUFMXWXeg=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.51 h1:F/9Sm6Y6k4LqDesZDPJCLxQGXNNHd/ZtJiWd0lCZKRk=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.51/go.mod h1:TKbzCHm43AoPyA+iLGGcruXd4AFhF8tOmLex2R9jWNQ=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 h1:IBAoD/1d8A8/1aA8g4MBVtTRHhXRiNAgwdbo/xRM2DI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23/go.mod h1:vfENuCM7dofkgKpYzuzf1VT1UKkA/YL3qanfBn7HCaA=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 h1:jSJjSBzw8VDIbWv+mmvBSP8ezsztMYJGH+eKqi9AmNs=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27/go.mod h1:/DAhLbFRgwhmvJdOfSm+WwikZrCuUJiA4WgJG0fTNSw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 h1:l+X4K77Dui85pIj5foXDhPlnqcNRG2QUyvca300lXh8=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27/go.mod h1:KvZXSFEXm6x84yE8qffKvT3x8J5clWnVFXphpohhzJ8=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27 h1:AmB5QxnD+fBFrg9LcqzkgF/CaYvMyU/BTlejG4t1S7Q=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.27/go.mod h1:Sai7P3xTiyv9ZUYO3IFxMnmiIP759/67iQbU4kdmkyU=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.8 h1:iwYS40JnrBeA9e9aI5S6KKN4EB2zR4iUVYN0nwVivz4=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.8/go.mod h1:Fm9Mi+ApqmFiknZtGpohVcBGvpTu542VC4XO9YudRi0=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8 h1:cWno7lefSH6Pp+mSznagKCgfDGeZRin66UvYUqAkyeA=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8/go.mod h1:tPD+VjU3ABTBoEJ3nctu5Nyg4P4yjqSH5bJGGkY4+XE=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.8 h1:/Mn7gTedG86nbpjT4QEKsN1D/fThiYe1qvq7WsBGNHg=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.8/go.mod h1:Ae3va9LPmvjj231ukHB6UeT8nS7wTPfC3tMZSZMwNYg=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.72.2 h1:a7aQ3RW+ug4IbhoQp29NZdc7vqrzKZZfWZSaQAXOZvQ=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.72.2/go.mod h1:xMekrnhmJ5aqmyxtmALs7mlvXw5xRh+eYjOjvrIIFJ4=
+github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 h1:YqtxripbjWb2QLyzRK9pByfEDvgg95gpC2AyDq4hFE8=
+github.com/aws/aws-sdk-go-v2/service/sso v1.24.9/go.mod h1:lV8iQpg6OLOfBnqbGMBKYjilBlf633qwHnBEiMSPoHY=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 h1:6dBT1Lz8fK11m22R+AqfRsFn8320K0T5DTGxxOQBSMw=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8/go.mod h1:/kiBvRQXBc6xeJTYzhSdGvJ5vm1tjaDEjH+MSeRJnlY=
+github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 h1:VwhTrsTuVn52an4mXx29PqRzs2Dvu921NpGk7y43tAM=
+github.com/aws/aws-sdk-go-v2/service/sts v1.33.6/go.mod h1:+8h7PZb3yY5ftmVLD7ocEoE98hdc8PoKS0H3wfx1dlc=
+github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
+github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
@@ -259,6 +295,9 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
@@ -708,6 +747,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/http/settings.go b/http/settings.go
index 002f6b19..ce90fcf6 100644
--- a/http/settings.go
+++ b/http/settings.go
@@ -35,7 +35,9 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
Torrent: d.settings.Torrent,
}
+ // Hide sensitive information.
data.Torrent.QbPassword = ""
+ data.Torrent.AccountKeySecret = ""
return renderJSON(w, r, data)
})
diff --git a/http/torrent.go b/http/torrent.go
index 9f146325..f9a42cf4 100644
--- a/http/torrent.go
+++ b/http/torrent.go
@@ -43,7 +43,6 @@ var torrentPostHandler = withPermTorrent(func(w http.ResponseWriter, r *http.Req
if err != nil {
return errToStatus(err), err
}
- fPath := file.RealPath()
var body users.CreateTorrentBody
if r.Body != nil {
@@ -53,7 +52,7 @@ var torrentPostHandler = withPermTorrent(func(w http.ResponseWriter, r *http.Req
defer r.Body.Close()
}
- err = d.Torrent.MakeTorrent(fPath, body)
+ err = d.Torrent.MakeTorrent(file, body)
if err != nil {
return http.StatusInternalServerError, err
}
diff --git a/settings/torrent.go b/settings/torrent.go
index 373da377..0a3a7c97 100644
--- a/settings/torrent.go
+++ b/settings/torrent.go
@@ -1,8 +1,13 @@
package settings
type Torrent struct {
- TrackersListUrl string `json:"trackersListUrl"`
- QbUrl string `json:"qbUrl"`
- QbUsername string `json:"qbUsername"`
- QbPassword string `json:"qbPassword"`
+ TrackersListUrl string `json:"trackersListUrl"`
+ QbUrl string `json:"qbUrl"`
+ QbUsername string `json:"qbUsername"`
+ QbPassword string `json:"qbPassword"`
+ AccountId string `json:"accountId"`
+ AccountKeyId string `json:"accountKeyId"`
+ AccountKeySecret string `json:"accountKeySecret"`
+ Bucket string `json:"bucket"`
+ Domain string `json:"domain"`
}
diff --git a/torrent/r2_client.go b/torrent/r2_client.go
new file mode 100644
index 00000000..22c1a4b7
--- /dev/null
+++ b/torrent/r2_client.go
@@ -0,0 +1,80 @@
+package torrent
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+ "sync"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/config"
+ "github.com/aws/aws-sdk-go-v2/credentials"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+ "github.com/aws/aws-sdk-go-v2/service/s3/types"
+)
+
+var (
+ client *s3.Client
+ once sync.Once
+)
+
+// InitializeClient initializes the S3 client and ensures it's only done once.
+func InitializeClient(accountId, accessKeyId, accessKeySecret string) {
+ once.Do(func() {
+ cfg, err := config.LoadDefaultConfig(context.TODO(),
+ config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKeyId, accessKeySecret, "")),
+ config.WithRegion("auto"),
+ )
+ if err != nil {
+ log.Fatalf("failed to load config: %v", err)
+ }
+
+ client = s3.NewFromConfig(cfg, func(o *s3.Options) {
+ o.BaseEndpoint = aws.String(fmt.Sprintf("https://%s.r2.cloudflarestorage.com", accountId))
+ })
+ })
+}
+
+// GetClient returns the initialized S3 client.
+func GetClient() *s3.Client {
+ if client == nil {
+ log.Fatal("S3 client is not initialized. Call InitializeClient first.")
+ }
+ return client
+}
+
+// ListFiles lists all files in the specified bucket.
+func listFiles(bucketName string) ([]types.Object, error) {
+ client := GetClient()
+ output, err := client.ListObjectsV2(context.TODO(), &s3.ListObjectsV2Input{
+ Bucket: &bucketName,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to list files: %w", err)
+ }
+ return output.Contents, nil
+}
+
+// UploadFile uploads a file to the specified bucket.
+func uploadHandler(bucketName, key, filePath string, c chan string) error { //nolint:interfacer
+ client := GetClient()
+
+ // Open the file
+ file, err := os.Open(filePath)
+ if err != nil {
+ return fmt.Errorf("failed to open file: %w", err)
+ }
+ defer file.Close()
+
+ // Upload the file
+ _, err = client.PutObject(context.TODO(), &s3.PutObjectInput{
+ Bucket: &bucketName,
+ Key: &key,
+ Body: file,
+ })
+ if err != nil {
+ return fmt.Errorf("failed to upload file: %w", err)
+ }
+ return nil
+}
diff --git a/torrent/torrent.go b/torrent/torrent.go
index be058d0a..1b1f327d 100644
--- a/torrent/torrent.go
+++ b/torrent/torrent.go
@@ -7,6 +7,7 @@ import (
"os/exec"
"strings"
+ "github.com/filebrowser/filebrowser/v2/files"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
@@ -16,7 +17,8 @@ type Torrent struct {
*users.User
}
-func (t *Torrent) MakeTorrent(fPath string, body users.CreateTorrentBody) error {
+func (t *Torrent) MakeTorrent(file *files.FileInfo, body users.CreateTorrentBody) error {
+ fPath := file.RealPath()
tPath := fPath + ".torrent"
// 设置 mktorrent 命令的选项
@@ -33,8 +35,37 @@ func (t *Torrent) MakeTorrent(fPath string, body users.CreateTorrentBody) error
WebSeeds: body.WebSeeds,
}
- args := buildArgs(opts)
+ // 上传到 R2
+ if body.R2 {
+ // var bucketName = "moezakura"
+ // var accountId = "6a59886e546396fc9076ec50764dc9f3"
+ // var accessKeyId = "d65f9e3347d046e0583a8d846aa8cb46"
+ // var accessKeySecret = "a8a57f4d1525eada05f7e553815a89c4da0a3b28745eaddea89e4c52334f056e"
+ var accountId = t.Settings.Torrent.AccountId
+ var accessKeyId = t.Settings.Torrent.AccountKeyId
+ var accessKeySecret = t.Settings.Torrent.AccountKeySecret
+ var bucketName = t.Settings.Torrent.Bucket
+
+ // will only be called once
+ InitializeClient(accountId, accessKeyId, accessKeySecret)
+
+ // remove first slash
+ var key = file.Path[1:]
+ sigc := make(chan string)
+ go uploadHandler(bucketName, key, fPath, sigc)
+ // result := <-sigc
+ // fmt.Println(result)
+
+ // join domain and key to url
+ // eg: domain: download.moezakura.click, key: test.txt
+ // url: https://download.moezakura.click/test.txt
+ var url = "https://" + t.Torrent.Domain + "/" + key
+ opts.WebSeeds = append(opts.WebSeeds, url)
+ }
+
+ // 调用 mktorrent 命令
+ args := buildArgs(opts)
cmd := exec.Command("mktorrent", args...)
err := cmd.Run()
diff --git a/users/torrent.go b/users/torrent.go
index 0a932125..6703966d 100644
--- a/users/torrent.go
+++ b/users/torrent.go
@@ -7,6 +7,7 @@ type CreateTorrentBody struct {
Name string `json:"name"`
PieceLen int `json:"pieceLen"`
Private bool `json:"private"`
+ R2 bool `json:"r2"`
Source string `json:"source"`
WebSeeds []string `json:"webSeeds"`
}