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"` }