From ba8b163b047187709c833aab5ee286fcf419271e Mon Sep 17 00:00:00 2001 From: Meng Sen Date: Mon, 21 Oct 2024 13:58:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=20Bitmagnet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Meng Sen --- .github/README.md | 1 + README.md | 1 + apps/bitmagnet/0.9.5/data.yml | 82 ++++++++++++++++++++++ apps/bitmagnet/0.9.5/docker-compose.yml | 36 ++++++++++ apps/bitmagnet/0.9.5/scripts/init.sh | 15 ++++ apps/bitmagnet/0.9.5/scripts/uninstall.sh | 10 +++ apps/bitmagnet/0.9.5/scripts/upgrade.sh | 15 ++++ apps/bitmagnet/README.md | 60 ++++++++++++++++ apps/bitmagnet/data.yml | 15 ++++ apps/bitmagnet/logo.png | Bin 0 -> 13804 bytes 10 files changed, 235 insertions(+) create mode 100644 apps/bitmagnet/0.9.5/data.yml create mode 100644 apps/bitmagnet/0.9.5/docker-compose.yml create mode 100644 apps/bitmagnet/0.9.5/scripts/init.sh create mode 100644 apps/bitmagnet/0.9.5/scripts/uninstall.sh create mode 100644 apps/bitmagnet/0.9.5/scripts/upgrade.sh create mode 100644 apps/bitmagnet/README.md create mode 100644 apps/bitmagnet/data.yml create mode 100644 apps/bitmagnet/logo.png diff --git a/.github/README.md b/.github/README.md index 5a8eeab2..de95ae9f 100644 --- a/.github/README.md +++ b/.github/README.md @@ -87,6 +87,7 @@ | 🟢 | | AList | https://alist.nn.ci/ | 一款支持多重存储的文件列表程序 | | | 🟢 | | Artalk | https://artalk.js.org/ | 一个自托管的评论系统 | | | 🟢 | | Bark | https://bark.day.app/ | 一款注重隐私、安全可控的自定义通知推送工具 | | +| 🟢 | | Bitmagnet | https://bitmagnet.io/ | 自托管的 BitTorrent 索引器 | | | 🟢 | | Casdoor | https://casdoor.org/ | 身份和访问管理(IAM)/单点登录(SSO)平台 | | | 🟢 | | Certimate | https://docs.certimate.me/ | SSL证书管理工具 | | | 🟢 | | Cookie Cloud | https://github.com/easychen/CookieCloud/ | CookieCloud是一个和自架服务器同步浏览器Cookie和LocalStorage的小工具 | | diff --git a/README.md b/README.md index 97f18a1a..b10c2931 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ | 🟢 | | AList | https://alist.nn.ci/ | 一款支持多重存储的文件列表程序 | | | 🟢 | | Artalk | https://artalk.js.org/ | 一个自托管的评论系统 | | | 🟢 | | Bark | https://bark.day.app/ | 一款注重隐私、安全可控的自定义通知推送工具 | | +| 🟢 | | Bitmagnet | https://bitmagnet.io/ | 自托管的 BitTorrent 索引器 | | | 🟢 | | Casdoor | https://casdoor.org/ | 身份和访问管理(IAM)/单点登录(SSO)平台 | | | 🟢 | | Certimate | https://docs.certimate.me/ | SSL证书管理工具 | | | 🟢 | | Cookie Cloud | https://github.com/easychen/CookieCloud/ | CookieCloud是一个和自架服务器同步浏览器Cookie和LocalStorage的小工具 | | diff --git a/apps/bitmagnet/0.9.5/data.yml b/apps/bitmagnet/0.9.5/data.yml new file mode 100644 index 00000000..d8b1def5 --- /dev/null +++ b/apps/bitmagnet/0.9.5/data.yml @@ -0,0 +1,82 @@ +additionalProperties: + formFields: + - child: + default: "" + envKey: PANEL_POSTGRES_SERVICE + required: true + type: service + default: postgresql + envKey: PANEL_POSTGRES_TYPE + labelZh: Postgres 服务 (前置检查) + labelEn: Postgres Service (Pre-check) + required: true + type: apps + values: + - label: PostgreSQL + value: postgresql + - default: "/home/bitmagnet" + edit: true + envKey: BITMAGNET_ROOT_PATH + labelZh: 数据持久化路径 + labelEn: Data persistence path + required: true + type: text + - default: 3333 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelZh: WebUI 端口 + labelEn: WebUI port + required: true + rule: paramPort + type: number + - default: 3334 + edit: true + envKey: PANEL_APP_PORT_BT + labelZh: BitTorrent 端口 + labelEn: BitTorrent port + required: true + rule: paramPort + type: number + - default: "127.0.0.1:5432" + edit: true + envKey: POSTGRES_HOST + labelZh: 数据库 主机地址 + labelEn: Database Host + required: true + type: text + - default: "bitmagnet" + edit: true + envKey: POSTGRES_NAME + labelZh: 数据库 名称 + labelEn: Database Name + required: true + rule: paramCommon + type: text + - default: "bitmagnet" + edit: true + envKey: POSTGRES_USER + labelZh: 数据库 用户名 + labelEn: Database Username + required: true + type: text + - default: "" + edit: true + envKey: POSTGRES_PASSWORD + labelZh: 数据库 密码 + labelEn: Database Password + random: true + required: true + rule: paramComplexity + type: password + - default: "true" + edit: true + envKey: TMDB_ENABLED + labelZh: 获取 TMDB 元数据 + labelEn: Fetch TMDB metadata + required: true + type: select + values: + - label: 允许 + value: "true" + - label: 禁止 + value: "false" diff --git a/apps/bitmagnet/0.9.5/docker-compose.yml b/apps/bitmagnet/0.9.5/docker-compose.yml new file mode 100644 index 00000000..9e90e451 --- /dev/null +++ b/apps/bitmagnet/0.9.5/docker-compose.yml @@ -0,0 +1,36 @@ +networks: + 1panel-network: + external: true + +services: + bitmagnet: + image: ghcr.io/bitmagnet-io/bitmagnet:v0.9.5 + container_name: ${CONTAINER_NAME} + labels: + createdBy: "Apps" + restart: always + networks: + - 1panel-network + ports: + - ${PANEL_APP_PORT_HTTP}:3333 + - ${PANEL_APP_PORT_BT}:3334/tcp + - ${PANEL_APP_PORT_BT}:3334/udp + env_file: + - /etc/1panel/envs/global.env + - ${ENV_FILE:-/etc/1panel/envs/default.env} + volumes: + - ${BITMAGNET_ROOT_PATH}/config:/root/.config/bitmagnet + - ${BITMAGNET_ROOT_PATH}/bitmagnet:/root/.local/share/bitmagnet + environment: + - LOG_FILE_ROTATOR_ENABLED=true + - LOG_LEVEL=info + - LOG_DEVELOPMENT=false + - LOG_JSON=false + - DHT_CRAWLER_SAVE_FILES_THRESHOLD=100 + - PROCESSOR_CONCURRENCY=1 + - TMDB_ENABLED=true + - TMDB_API_KEY=your_api_key + command: + - worker + - run + - --all diff --git a/apps/bitmagnet/0.9.5/scripts/init.sh b/apps/bitmagnet/0.9.5/scripts/init.sh new file mode 100644 index 00000000..77b84912 --- /dev/null +++ b/apps/bitmagnet/0.9.5/scripts/init.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + # setup-1 add default values + CURRENT_DIR=$(pwd) + sed -i '/^ENV_FILE=/d' .env + echo "ENV_FILE=${CURRENT_DIR}/.env" >> .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/bitmagnet/0.9.5/scripts/uninstall.sh b/apps/bitmagnet/0.9.5/scripts/uninstall.sh new file mode 100644 index 00000000..c86c4fbc --- /dev/null +++ b/apps/bitmagnet/0.9.5/scripts/uninstall.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/bitmagnet/0.9.5/scripts/upgrade.sh b/apps/bitmagnet/0.9.5/scripts/upgrade.sh new file mode 100644 index 00000000..77b84912 --- /dev/null +++ b/apps/bitmagnet/0.9.5/scripts/upgrade.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + # setup-1 add default values + CURRENT_DIR=$(pwd) + sed -i '/^ENV_FILE=/d' .env + echo "ENV_FILE=${CURRENT_DIR}/.env" >> .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/bitmagnet/README.md b/apps/bitmagnet/README.md new file mode 100644 index 00000000..c4e1ab3c --- /dev/null +++ b/apps/bitmagnet/README.md @@ -0,0 +1,60 @@ +# Bitmagnet + +自托管的 BitTorrent 索引器,DHT 爬虫,内容分类器和带 Web UI,GraphQL API 以及 Servarr 堆栈集成的 torrent 搜索引擎。 + +![Kimai](https://file.lifebus.top/imgs/bitmagnet_cover.png) + +![](https://img.shields.io/badge/%E6%96%B0%E7%96%86%E8%90%8C%E6%A3%AE%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E5%B7%A5%E4%BD%9C%E5%AE%A4-%E6%8F%90%E4%BE%9B%E6%8A%80%E6%9C%AF%E6%94%AF%E6%8C%81-blue) + +## 简介 + +DHT 爬虫是 Bitmagnet 的杀手锏,使其独一无二。那么它是什么呢? Translation: + +你可能知道,可以在你的 BitTorrent 客户端中启用 DHT,这允许你找到正在向分布式哈希表(DHT)宣布磁贴哈希的对等方,而不是向集中式跟踪器。 +DHT 的较不为人知的功能是,它允许您爬取它所知道的信息哈希。这就是 Bitmagnet 的 DHT 爬虫的工作方式 - 它爬取 DHT +网络,请求每个发现的信息哈希的元数据。然后通过尝试对其进行分类并将其与已知的内容关联(如电影和电视节目)进一步丰富这些元数据。 +然后允许你搜索它所索引的一切。 + +这意味着 Bitmagnet 不依赖于任何外部跟踪器或磁力链接索引器。它是一个自包含、自托管的磁力链接索引器,通过 DHT +连接到全球网络中的对等节点,并不断发现新的内容。 + +## 功能与路线图 + +### 当前已实现的功能 + +- [x] DHT 爬虫和协议实现 +- [x] 通用的 BitTorrent 索引器:bitmagnet 可以从任何来源索引磁力链接,而不仅仅是 DHT 网络——目前这仅可以通过 `/import` + 端点实现;更友好的方法正在开发中,请参见以下高优先级功能 +- [x] 一个高度可定制的内容分类器,目前可以识别多种类型的内容,以及与之相关的关键属性,如语言、分辨率、来源(蓝光、网络翻录等),并从包括电影数据库在内的多个数据源补充信息。 +- [x] [一个用于从任何来源摄入磁力链接的导入工具,例如 RARBG 备份](https://bitmagnet.io/guides/import.html) +- [x] 翻译文本: torrent 搜索引擎 +- [x] GraphQL API:当前提供单个搜索查询;还包含一个嵌入式 GraphQL playground 在 `/graphql` +- [x] 在 Angular 中实现的网络用户界面:当前这是一个简单的单页应用,通过 GraphQL API 提供搜索查询的用户界面 +- [x] [一个与 Torznab 兼容的端点,用于与 Serverr 堆栈集成](https://bitmagnet.io/guides/servarr- [ ]integration.html) + +### 高优先级功能尚未实现 + +- [ ] 一个 WebUI 仪表板,显示诸如爬虫吞吐量、任务队列、数据库大小等信息。 +- [ ] 认证,API 密钥,访问级别等。 +- [ ] 管理员 API,一般来说,一个更完整的 GraphQL API +- [ ] 更完整的网络 UI +- [ ] 保存了对特定内容的搜索,以启用除以下功能外的自定义 feeds +- [ ] 与 Prowlarr 索引器代理的双向集成:目前,Bitmagnet 可以作为 Prowlarr 中的索引器添加;双向集成将允许 Bitmagnet 从 + Prowlarr 中配置的任何索引器爬取内容,解锁许多新的内容来源 +- [ ] 更多文档和更多测试! + +### 管道梦想特性 + +事情开始变得有些模糊。目前所有关注点都在实现上述核心功能,但这些想法在未来可能会被探索: + +- [ ] 原地播种:在您的计算机上识别属于索引磁贴的文件,并在移动、重命名或删除磁贴的部分后,允许这些文件原地播种 +- [ ] 与流行的 BitTorrent 客户端集成 +- [ ] 某种联盟:允许朋友连接实例并汇集索引努力,可能涉及众包手动内容策展,以补充自动分类器 +- [ ] 看起来像是去中心化的私人追踪器;我可能指的是部分基于个人信任,并手动剔除任何不良行为者的东西;我可能会对创建看起来有点像 + Tribler 的东西持谨慎态度,尽管这是一个有趣的研究项目,但似乎已经证明,在协议层面上实现信任、声誉和隐私的开销太大,无法成为与原始的 + BitTorrent 相比具有吸引力的替代方案,尽管 BitTorrent 存在一些缺陷 +- [ ] BitTorrent v2 协议的支持:是否会有更广泛的采用使其成为有价值的功能还有待观察 + +--- + +![Ms Studio](https://file.lifebus.top/imgs/ms_blank_001.png) diff --git a/apps/bitmagnet/data.yml b/apps/bitmagnet/data.yml new file mode 100644 index 00000000..2b5fc0fc --- /dev/null +++ b/apps/bitmagnet/data.yml @@ -0,0 +1,15 @@ +additionalProperties: + key: bitmagnet + name: Bitmagnet + tags: + - WebSite + - Middleware + - Local + shortDescZh: 自托管的 BitTorrent 索引器 + shortDescEn: Self-hosted BitTorrent indexer + type: website + crossVersionUpdate: true + limit: 0 + website: https://bitmagnet.io/ + github: https://github.com/bitmagnet-io/bitmagnet/ + document: https://bitmagnet.io/ diff --git a/apps/bitmagnet/logo.png b/apps/bitmagnet/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bbdbe1949fed79cdb0149fa7fa643221d1a8c0c1 GIT binary patch literal 13804 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