diff --git a/Dockerfile b/Dockerfile index 40a91a06..190dd8a7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,9 @@ FROM alpine:latest RUN apk --update add ca-certificates \ mailcap \ curl \ - jq + jq \ + gcompat \ + mktorrent COPY healthcheck.sh /healthcheck.sh RUN chmod +x /healthcheck.sh # Make the script executable @@ -16,4 +18,4 @@ EXPOSE 80 COPY docker_config.json /.filebrowser.json COPY filebrowser /filebrowser -ENTRYPOINT [ "/filebrowser" ] \ No newline at end of file +ENTRYPOINT [ "/filebrowser" ] diff --git a/Dockerfile.s6 b/Dockerfile.s6 index 233feb22..9e4a1e9d 100644 --- a/Dockerfile.s6 +++ b/Dockerfile.s6 @@ -2,7 +2,8 @@ FROM ghcr.io/linuxserver/baseimage-alpine:3.17 RUN apk --update add ca-certificates \ mailcap \ - curl + curl \ + mktorrent HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \ CMD curl -f http://localhost/health || exit 1 @@ -13,4 +14,4 @@ COPY filebrowser /usr/bin/filebrowser # ports and volumes VOLUME /srv /config /database -EXPOSE 80 \ No newline at end of file +EXPOSE 80 diff --git a/Dockerfile.s6.aarch64 b/Dockerfile.s6.aarch64 index d7f3dcee..821b76a4 100644 --- a/Dockerfile.s6.aarch64 +++ b/Dockerfile.s6.aarch64 @@ -2,7 +2,8 @@ FROM ghcr.io/linuxserver/baseimage-alpine:arm64v8-3.17 RUN apk --update add ca-certificates \ mailcap \ - curl + curl \ + mktorrent HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \ CMD curl -f http://localhost/health || exit 1 diff --git a/Dockerfile.s6.armhf b/Dockerfile.s6.armhf index 17bd1def..158989d3 100644 --- a/Dockerfile.s6.armhf +++ b/Dockerfile.s6.armhf @@ -2,7 +2,8 @@ FROM ghcr.io/linuxserver/baseimage-alpine:arm32v7-3.17 RUN apk --update add ca-certificates \ mailcap \ - curl + curl \ + mktorrent HEALTHCHECK --start-period=2s --interval=5s --timeout=3s \ CMD curl -f http://localhost/health || exit 1 diff --git a/auth/hook.go b/auth/hook.go index c659e57b..f4c9c660 100644 --- a/auth/hook.go +++ b/auth/hook.go @@ -216,6 +216,7 @@ func (a *HookAuth) GetUser(d *users.User) *users.User { Delete: isAdmin || a.Fields.GetBoolean("user.perm.delete", d.Perm.Delete), Share: isAdmin || a.Fields.GetBoolean("user.perm.share", d.Perm.Share), Download: isAdmin || a.Fields.GetBoolean("user.perm.download", d.Perm.Download), + Torrent: isAdmin || a.Fields.GetBoolean("user.perm.torrent", d.Perm.Torrent), } user := users.User{ ID: d.ID, diff --git a/cmd/config.go b/cmd/config.go index de55c28e..0ffd3f0e 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -181,6 +181,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete) fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share) fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download) + fmt.Fprintf(w, "\t\tTorrent:\t%t\n", set.Defaults.Perm.Torrent) w.Flush() b, err := json.MarshalIndent(auther, "", " ") diff --git a/cmd/root.go b/cmd/root.go index 27c0a8db..a40a923d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -335,6 +335,10 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) { Delete: true, Share: true, Download: true, + Torrent: true, + }, + CreateBody: users.CreateTorrentBody{ + Date: true, }, }, AuthMethod: "", diff --git a/cmd/users.go b/cmd/users.go index d3f97da6..7a604f5a 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -30,7 +30,7 @@ func printUsers(usrs []*users.User) { fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock") for _, u := range usrs { - fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n", + fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t%t\t\n", u.ID, u.Username, u.Scope, @@ -45,6 +45,7 @@ func printUsers(usrs []*users.User) { u.Perm.Delete, u.Perm.Share, u.Perm.Download, + u.Perm.Torrent, u.LockPassword, ) } @@ -77,6 +78,7 @@ func addUserFlags(flags *pflag.FlagSet) { flags.String("locale", "en", "locale for users") flags.String("viewMode", string(users.ListViewMode), "view mode for users") flags.Bool("singleClick", false, "use single clicks only") + flags.String("trackersListUrl", "https://cf.trackerslist.com/all.txt", "tracker lists url") } func getViewMode(flags *pflag.FlagSet) users.ViewMode { @@ -115,6 +117,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all defaults.Perm.Share = mustGetBool(flags, flag.Name) case "perm.download": defaults.Perm.Download = mustGetBool(flags, flag.Name) + case "perm.torrent": + defaults.Perm.Torrent = mustGetBool(flags, flag.Name) case "commands": commands, err := flags.GetStringSlice(flag.Name) checkErr(err) diff --git a/cmd/users_update.go b/cmd/users_update.go index 822bb6dc..2ee54e24 100644 --- a/cmd/users_update.go +++ b/cmd/users_update.go @@ -48,6 +48,7 @@ options you want to change.`, Perm: user.Perm, Sorting: user.Sorting, Commands: user.Commands, + CreateBody: user.CreateBody, } getUserDefaults(flags, &defaults, false) user.Scope = defaults.Scope @@ -57,6 +58,7 @@ options you want to change.`, user.Perm = defaults.Perm user.Commands = defaults.Commands user.Sorting = defaults.Sorting + user.CreateBody = defaults.CreateBody user.LockPassword = mustGetBool(flags, "lockPassword") if newUsername != "" { diff --git a/frontend/public/svg/qbittorrent.svg b/frontend/public/svg/qbittorrent.svg new file mode 100644 index 00000000..01c99f79 --- /dev/null +++ b/frontend/public/svg/qbittorrent.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/public/svg/torrent.svg b/frontend/public/svg/torrent.svg new file mode 100644 index 00000000..a3c55155 --- /dev/null +++ b/frontend/public/svg/torrent.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index abc189dc..ddc16709 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -3,7 +3,8 @@ import * as share from "./share"; import * as users from "./users"; import * as settings from "./settings"; import * as pub from "./pub"; +import * as torrent from "./torrent"; import search from "./search"; import commands from "./commands"; -export { files, share, users, settings, pub, commands, search }; +export { files, share, users, settings, pub, torrent, commands, search }; diff --git a/frontend/src/api/torrent.ts b/frontend/src/api/torrent.ts new file mode 100644 index 00000000..16cecf9d --- /dev/null +++ b/frontend/src/api/torrent.ts @@ -0,0 +1,56 @@ +import { fetchURL, fetchJSON, removePrefix, createURL } from "./utils"; + +export async function fetchDefaultOptions() { + const url = `/api/torrent` + return fetchJSON(url); +} + +export async function makeTorrent( + url: string, + announces: string[], + comment: string, + date: boolean, + name: string, + pieceLen: number, + privateFlag: boolean, + source: string, + webSeeds: string[] +) { + // Construct the URL for torrent creation API + url = removePrefix(url); + url = `/api/torrent${url}`; + + let body = "{}"; + if (announces.length > 0) { + body = JSON.stringify({ + announces: announces, + comment: comment, + date: date, + name: name, + pieceLen: pieceLen, + private: privateFlag, + source: source, + webSeeds: webSeeds, + }); + } + + // Send POST request to create the torrent + return fetchJSON(url, { + method: "POST", + body: body, + }); +} + +export function publish( + url: string +) { + url = removePrefix(url); + url = `/api/publish${url}`; + + let body = "{}"; + + return fetchJSON(url, { + method: "POST", + body: body, + }); +} \ No newline at end of file diff --git a/frontend/src/components/prompts/Prompts.vue b/frontend/src/components/prompts/Prompts.vue index 4ecde794..7b3147fd 100644 --- a/frontend/src/components/prompts/Prompts.vue +++ b/frontend/src/components/prompts/Prompts.vue @@ -15,6 +15,8 @@ import Delete from "./Delete.vue"; import DeleteUser from "./DeleteUser.vue"; import Download from "./Download.vue"; import Rename from "./Rename.vue"; +import Torrent from "./Torrent.vue"; +import Publish from "./Publish.vue"; import Move from "./Move.vue"; import Copy from "./Copy.vue"; import NewFile from "./NewFile.vue"; @@ -37,6 +39,8 @@ const components = new Map([ ["help", Help], ["delete", Delete], ["rename", Rename], + ["torrent", Torrent], + ["publish", Publish], ["move", Move], ["copy", Copy], ["newFile", NewFile], diff --git a/frontend/src/components/prompts/Publish.vue b/frontend/src/components/prompts/Publish.vue new file mode 100644 index 00000000..4f8d4fc5 --- /dev/null +++ b/frontend/src/components/prompts/Publish.vue @@ -0,0 +1,82 @@ + + + diff --git a/frontend/src/components/prompts/Torrent.vue b/frontend/src/components/prompts/Torrent.vue new file mode 100644 index 00000000..2ed3a0b7 --- /dev/null +++ b/frontend/src/components/prompts/Torrent.vue @@ -0,0 +1,209 @@ + + + diff --git a/frontend/src/components/settings/Permissions.vue b/frontend/src/components/settings/Permissions.vue index 13d2b936..ae16be2a 100644 --- a/frontend/src/components/settings/Permissions.vue +++ b/frontend/src/components/settings/Permissions.vue @@ -36,6 +36,10 @@ {{ $t("settings.perm.share") }}

+

+ + {{ $t("settings.perm.torrent") }} +

diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 1aea4134..92a7dcab 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -14,6 +14,7 @@ "folder": "文件夹", "hideDotfiles": "不显示隐藏文件", "info": "信息", + "torrent": "制作 Torrent", "more": "更多", "move": "移动", "moveFile": "移动文件", @@ -41,7 +42,9 @@ "openFile": "打开文件", "continue": "继续", "fullScreen": "切换全屏", - "discardChanges": "放弃更改" + "discardChanges": "放弃更改", + "detailed": "转到详细视图", + "compact": "转到精简视图" }, "download": { "downloadFile": "下载文件", @@ -117,6 +120,8 @@ "fileInfo": "文件信息", "filesSelected": "已选择 {count} 个文件。", "lastModified": "最后修改", + "makeTorrentMessageSingle": "你确定要创建这个文件的种子吗?", + "makeTorrentMessageMultiple": "你确定要创建这 {count} 个文件的种子吗?", "move": "移动", "moveMessage": "请选择目标目录:", "newArchetype": "创建一个基于原型的新帖子。你的文件将会创建在内容文件夹中。", @@ -140,7 +145,16 @@ "optionalPassword": "密码(选填,不填即无密码)", "resolution": "分辨率", "deleteUser": "你确定要删除这个用户吗?", - "discardEditorChanges": "你确定要放弃所做的更改吗?" + "discardEditorChanges": "你确定要放弃所做的更改吗?", + "pieceLength": "分片大小:", + "auto": "自动", + "trackersList": "Tracker URL:", + "comment": "注释:", + "webSeeds": "Web 种子 URL:", + "source": "源:", + "includeDate": "写入创建日期", + "privateTorrent": "私有 torrent (不会在DHT网络上分发)", + "publishMessage": "你确定要发布这个种子吗?" }, "search": { "images": "图像", @@ -205,7 +219,8 @@ "execute": "执行命令", "modify": "编辑", "rename": "重命名或移动文件和文件夹", - "share": "分享文件" + "share": "分享文件", + "torrent": "BT制种" }, "permissions": "权限", "permissionsHelp": "你可以将该用户设置为管理员或单独选择各项权限。如果你选择了“管理员”,则其他的选项会被自动选中,同时该用户可以管理其他用户。\n", @@ -236,7 +251,16 @@ "userManagement": "用户管理", "userUpdated": "用户已更新!", "username": "用户名", - "users": "用户" + "users": "用户", + "torrentSettings": "BT设置", + "makeTorrent": "制种", + "makeTorrentSettingsDescription": "你可以在此设置BT种子(*.torrent)的默认参数。这些参数可以在创建种子时修改。", + "trackersListUrl": "Tracker URL 列表来源", + "publish": "发布", + "qbSettingsDescription": "你可以在此设置 qBittorrent WebUI 的地址、用户名和密码。", + "qbUrl": "qBittorrent WebUI 地址", + "qbUsername": "qBittorrent WebUI 用户名", + "qbPassword": "qBittorrent WebUI 密码" }, "sidebar": { "help": "帮助", @@ -252,7 +276,9 @@ "siteSettings": "网站设置" }, "success": { - "linkCopied": "链接已复制!" + "linkCopied": "链接已复制!", + "torrentCreated": "种子已创建!", + "torrentPublished": "种子已发布!" }, "time": { "days": "天", diff --git a/frontend/src/types/api.d.ts b/frontend/src/types/api.d.ts index 66685e5e..91286177 100644 --- a/frontend/src/types/api.d.ts +++ b/frontend/src/types/api.d.ts @@ -31,3 +31,14 @@ interface Share { interface SearchParams { [key: string]: string; } + +interface Torrent { + announces: string[]; + comment: string; + date: boolean; + name: string; + pieceLen: number; + private: boolean; + source: string; + webSeeds: string[]; +} \ No newline at end of file diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts index a2c19f76..ae989e40 100644 --- a/frontend/src/types/settings.d.ts +++ b/frontend/src/types/settings.d.ts @@ -8,6 +8,7 @@ interface ISettings { tus: SettingsTus; shell: string[]; commands: SettingsCommand; + torrent: SettingsTorrent; } interface SettingsDefaults { @@ -49,6 +50,13 @@ interface SettingsCommand { before_upload?: string[]; } +interface SettingsTorrent { + trackersListUrl?: string; + qbUrl?: string; + qbUsername?: string; + qbPassword?: string; +} + interface SettingsUnit { KB: number; MB: number; diff --git a/frontend/src/types/user.d.ts b/frontend/src/types/user.d.ts index b81806fc..e9e3d6cc 100644 --- a/frontend/src/types/user.d.ts +++ b/frontend/src/types/user.d.ts @@ -45,6 +45,7 @@ interface Permissions { share: boolean; shell: boolean; upload: boolean; + torrent: boolean; } interface Sorting { diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue index a26ac67e..9ced6f0b 100644 --- a/frontend/src/views/files/FileListing.vue +++ b/frontend/src/views/files/FileListing.vue @@ -12,6 +12,20 @@