当前位置: 首页 > news >正文

一种利用 qBittorrent 的 WebUI API 实现的检查BT种子的磁力链接是否可用的程序

文章目录

  • 一、问题背景
  • 二、WebUI API 介绍
    • 1. login 接口:api/v2/auth/login
    • 2. add 接口:api/v2/torrents/add
    • 3. properties 接口:api/v2/torrents/properties
    • 4. delete 接口:api/v2/torrents/delete
  • 三、流程图
  • 四、代码实现
    • 1. Retrofit 接口定义
    • 2. Repo类

一、问题背景

之前有利用 atomashpolskiy/bt:https://github.com/atomashpolskiy/bt 的 Java 库实现了用 Java / Kotlin 编写检测BT种子的磁力链接是否有可用 peers 的程序: https://blog.csdn.net/TeleostNaCl/article/details/151051936。由于使用的开源库,功能没有 qBittorrent 的那么丰富,导致有些种子在 qBittorrent 中可以使用的,但是在检测程序中报告无法下载,从而造成误判断。而 qBittorrent 提供了丰富的 WebUIAPI,是我们可以通过直接调用相关 API 而使用 qBittorrent 的功能。因此,本文将详细介绍使用 Kotlin 代码,使用 Retrofit 的响应式风格调用 qBittorrentAPI 去检查BT种子的磁力链接是否可用的程序。

二、WebUI API 介绍

详细的官方介绍文档如下:https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-5.0)

我们在此功能中只会用到四个接口(login 接口,add 接口,properties接口,delete 接口),本文将详细介绍他们的用法,其它接口可以参阅详细的官方介绍文档。

1. login 接口:api/v2/auth/login

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-5.0)#login
首先,我们需要调用 login 接口(api/v2/auth/login),使用 POST 方法传递用户名和账户,此时将尝试登录,如果登录成功,则会得到 Cookies 信息,此 Cookies 信息将会在后面调用其它接口的时候被传递作为身份凭证。

例如,官方示例如下:

curl -i --header 'Referer: http://localhost:8080' --data 'username=admin&password=adminadmin' http://localhost:8080/api/v2/auth/loginHTTP/1.1 200 OK
Content-Encoding:
Content-Length: 3
Content-Type: text/plain; charset=UTF-8
Set-Cookie: SID=hBc7TxF76ERhvIw0jQQ4LZ7Z1jQUV0tQ; path=/

2. add 接口:api/v2/torrents/add

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-5.0)#add-new-torrent
此接口是向 qBittorrent 中添加一个种子以便下载的核心接口,其使用 POST 方法可以传递多个参数,以适应不同的需求,详细的介绍如下:
在这里插入图片描述
我们这里需要用到四个参数:
urls:磁力链链接。为了便于程序的编写,我们只检测磁力连接形如 magnet:?xt=urn:btih:<info-hash> 的种子,因此我们使用 urls 参数。
paused:传递 true,使种子处于暂停状态。由于我们只需要检查其可用性,所以需要使其处于暂停状态。
skip_checking:传递 true,我们不需要下载文件,所以不需要 hash 校验。
tags:此参数可选。其可以给种子下载任务添加一个标签,将检测种子可用的任务与其它任务进行区分。使用 , 可以分割多个标签。

3. properties 接口:api/v2/torrents/properties

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-5.0)#get-torrent-generic-properties
此接口是查询种子状态的核心方法,使用 GET 方法传递种子的 Hash 值,其可以获取种子的大部分信息,参数如下:
在这里插入图片描述
我们检验种子有效性的时候,可以使用是否可以获取到种子元信息作为依据,而对于大部分种子来说,当未获取到元信息的时候,name 参数为种子的 hash 值,当获取到元信息之后,name 参数会将会使用种子名。因此,为了程序的简易性,我们将使用此作为种子是否可用的依据,基本可以涵盖大部分场景。在使用中,我们将定时轮询此接口,获取种子信息,一旦种子获取到元信息,我们即可返回种子可用。否则等超时之后(即在指定时间内都无法获取到元信息),则认为种子不可用。

4. delete 接口:api/v2/torrents/delete

https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-5.0)#delete-torrents
此接口用于将种子移除,使用 POST 方法,可以传递两个参数,删除指定 hash 值的种子任务吗,并指定是否需要移除文件。
在这里插入图片描述

三、流程图

在这里插入图片描述

四、代码实现

1. Retrofit 接口定义

class QBRetrofit {val retrofit: Retrofit = Retrofit.Builder().baseUrl("WebUI地址").client(OkHttpClient.Builder()// 自定义 cookies管理.cookieJar(cookieJar).build())// Gson 转换器.addConverterFactory(GsonConverterFactory.create()).build();fun qbApi(): QBApi = retrofit.create(QBApi::class.java)
}interface QBApi {/*** 登录到 qBittorrent*/@FormUrlEncoded@POST("api/v2/auth/login")suspend fun login(@Field("username") username: String,@Field("password") password: String): ResponseBody/*** 添加磁力链接种子*/@FormUrlEncoded@POST("api/v2/torrents/add")suspend fun addTorrent(@Field("urls") magnetLink: String,@Field("paused") paused: String = "true",@Field("skip_checking") skipChecking: String = "true",@Field("tags") tags: String? = null): ResponseBody/*** 获取种子详细信息*/@GET("api/v2/torrents/properties")suspend fun getTorrentProperties(@Query("hash") hash: String): Response<TorrentProperties>/*** 删除种子*/@POST("api/v2/torrents/delete")@FormUrlEncodedfun deleteTorrents(@Field("hashes") hashes: String,@Field("deleteFiles") deleteFiles: Boolean = true): Call<ResponseBody>
}

2. Repo类

/*** qBittorrent 的 Repo 类*/
class QBRepo {companion object {/*** 登录到 qBittorrent 的账户和密码*/private const val USERNAME = "admin"private const val PASSWORD = "adminadmin"/*** 登录成功的信息*/private const val LOGIN_SUCCESS = "Ok."/*** 测试种子的标签*/private const val TEST_TORRENT_TAG = "Test"/*** 检查 种子可用性的 默认次数*/private const val CHECK_AVAILABLE_COUNT = 60/*** 轮询检查种子可用性的 默认时长*/private const val CHECK_AVAILABLE_INTERVAL = 1000L}private val api by lazy { QBRetrofit().qbApi() }/*** 检查种子是否可用* * @param magnetLink 种子的磁力链* @param trackers 额外的tracker* @param checkCount 轮询检查种子是否可用的次数* @param checkInterval 轮询检查种子是否可用的时间间隔*/suspend fun isTorrentUrlAlive(magnetLink: String, trackers: List<String>,checkCount: Int = CHECK_AVAILABLE_COUNT,checkInterval: Long = CHECK_AVAILABLE_INTERVAL): Boolean = withContext(Dispatchers.IO) {var result = false// 获取hash值val hash = extractHashFromMagnet(magnetLink) ?: return@withContext falsetry {// 先尝试登录if (!login()) {return@withContext false}// 将 tracker 拼接到 磁力链之后val torrent = StringBuilder(magnetLink)trackers.forEach { tracker ->torrent.append("&tr=").append(tracker)}// 先将种子 以暂停方式 添加到 qBittorrent 中api.addTorrent(torrent.toString(), tags = TEST_TORRENT_TAG)// 添加进去之后 每秒循环检查种子是否可用var i = 0while (isActive && i++ < checkCount) {// 延迟delay(checkInterval)// 获取种子的信息val properties = api.getTorrentProperties(hash).body()val name = properties?.name?.lowercase()// 如果名字为空 则继续检查if (name.isNullOrBlank()) {continue}// 如果 种子的名字不是 hash 值 则表示 种子可用 返回trueif (name != hash) {result = truebreak}}} catch (e: Exception) {} finally {try {// 检测完成之后 要删除种子api.deleteTorrents(hash).execute()} catch (_: Exception) {}}return@withContext result}/*** 登录到 qBittorrent*/suspend fun login(): Boolean = withContext(Dispatchers.IO) {try {val response = api.login(USERNAME, PASSWORD)val body = response.string()body == LOGIN_SUCCESS} catch (e: Exception) {false}}/*** 从磁力链接中提取哈希值*/private fun extractHashFromMagnet(magnetLink: String): String? {return magnetLink.split("urn:btih:").getOrNull(1)?.split("&")?.first()?.lowercase()}
}
http://www.dtcms.com/a/434328.html

相关文章:

  • nodejs换源管理工具nrm
  • async/await的基本使用以及fetchAPI的部分细节
  • MySQL新学知识(一)
  • 小迪web自用笔记47
  • 前端如何优雅地生成唯一标识?——一份跨环境 UUID 工具函数的封装与实战
  • iBizModel 应用程序(PSSYSAPP)模型体系详解
  • iis 网站 起不来 temp文件夹html网站建设心得体会
  • Ubuntu防火墙端口管理指南
  • Ubuntu离线安装软件包
  • 山东电力建设网站泉州专业建站品牌
  • 微服务项目部署配置文件示例:从开发到生产的完整指南
  • 声卡驱动解决方案(电脑没有声音,麦克风没有声音)win11
  • 哈尔滨快速建站模板如意影院
  • 机器人、具身智能的起步——线性系统理论|【二】状态空间方程的解
  • 【数据结构】字典树
  • Rust Slint 实现控件拖动详细教程
  • 4. Pandas 数据选择、查询与修改
  • React新闻发布系统 角色列表篇
  • 网站常用插件wordpress自定义应用
  • 衡水手机网站建设淮安市盱眙县建设局网站
  • iPhone美区账号登录指南:轻松下载ChatGPT应用
  • AI大模型:(三)1.6 Dify工作流快速搭建数据可视化助手
  • 软件/网站安全需要以及解决方法
  • 做设备推广的网站学做网站用谁的书
  • python 做网站速度网站建设及托管合同
  • Coze源码分析-资源库-编辑工作流-后端源码-数据存储/安全/错误
  • 什么是Java反射机制?
  • 使用Docker安装Neo4j
  • 建立网站的步骤筝晃湖南岚鸿官网深圳专业建设网站哪个公司好
  • 20软件测试需求分析评审