基于qbittorrentapi实现批量加载种子跳检

本文最后更新于:8 天前

一、前言


之前在贴吧发过一个qbittorrent跳检的工具,但是也就是自己使用而已,并没有进行一些宣传以及分析过程。这次有机会也有人问,在这里介绍一下。

二、API介绍


个人之所以比较喜欢qbittorrent是因为其丰富的api可以进行一些DIY进行各种工具的开发。

操作首先需要开启webui:参考教程——Ubuntu安装qbittorrent并开启web服务。这里就不做赘述了,我们需要记录下端口、账号和密码后续使用。

api的介绍文档:https://qbittorrent-api.readthedocs.io/en/latest/

简单代码演示:

from qbittorrentapi import Client, LoginFailed

# 获取客户端实例
qb = Client(host='localhost:2021', username='admin', password='123456')

# 客户端进行登录
try:
    qb.auth_log_in()
except LoginFailed as e:
    print(e)

# 输出客户端信息
print(f'qBittorrent: {qb.app.version}')
print(f'qBittorrent Web API: {qb.app.web_api_version}')
for k,v in qb.app.build_info.items(): print(f'{k}: {v}')

# 抓取前10个种子的部分信息:哈希值截取,名称,状态
for torrent in qb.torrents_info()[0:10]:
    print(f'{torrent.hash[-6:]}: {torrent.name} ({torrent.state})')
## 上述代码运行结果
qBittorrent: v4.2.5
qBittorrent Web API: 2.5.1

# 编译库版本信息
bitness: 64
boost: 1.72.0
libtorrent: 1.2.6.0
openssl: 1.1.1g
qt: 5.13.2
zlib: 1.2.11

# 种子部分信息
7aef57: Crying.Out.In.Love.2016.2160p.WEB-DL.AAC2.0.H265-tomorrow505.mkv (stalledUP)
ab961d: Van.Helsing.2004.720p.BluRay.DTS.x264-RuDE (stalledUP)
044c69: My.Roommate.is.a.Gumiho.S01E03.210602.720p-NEXT.mp4 (stalledUP)
0ac220: Sommaren.med.Monika.1953.1080p.BluRay.x264-DON (stalledUP)
51edf3: 3.10.To.Yuma.2007.1080p.BluRay.DTS.x264.D-Z0N3.mkv (stalledUP)
cd58d3: Incognito.1997.1080p.AMZN.WEB-DL.DDP2.0.x264-KAMIKAZE (stalledUP)
12902d: La.mala.educacion.2004.1080p.BluRay.x264.AC3-HDChina.mkv (stalledUP)
943ff4: The.Memory.Eraser.2020.720p.BluRay.x264-WiKi (stalledUP)
2e2219: Wedding.Dress.2009.HDTV.720p.x264-HDCTV (stalledUP)
48b7b4: Avant.Le.Deluge.1954.REMASTERED.FRENCH.720p.BluRay.DTS.x264-NEO (stalledUP)

同时我们可以找到添加种子功能的api:其中是有跳检参数的。

torrents_add(urls=None, torrent_files=None**,** save_path=None**,** cookie=None**,** category=None**,** is_skip_checking=None**,** is_paused=None**,** is_root_folder=None**,** rename=None**,** upload_limit=None**,** download_limit=None**,** use_auto_torrent_management=None**,** is_sequential_download=None**,** is_first_last_piece_priority=None**,** tags=None**,** content_layout=None**,** ratio_limit=None**,** seeding_time_limit=None**,** kwargs)**

Add one or more torrents by URLs and/or torrent files. 通过链接或者种子文件添加一个或多个种子。

参数列表:

  • urls – 对应于通过链接添加种子,可以是磁链或者是种子的下载链接
  • torrent_files – 可以有几种文件类型: 1) 读取了的单文件种子数据类型 2) 使用open(, ‘rb’) 打开的单种子文件句柄 3) 单种子文件路径 4) 多个可迭代的上述文件类型 5) 字典类型,不多做说明。我们演示单文件路径进行添加。
  • save_path – 种子下载文件的保存路径
  • cookie – 使用链接添加种子的时候添加cookie对象
  • category – 分类
  • is_skip_checking – 是否跳检选项
  • is_paused – 是否暂停种子选项
  • is_root_folder – 是否创建根目录 (superseded by content_layout with v4.3.2)
  • rename –是否重命名
  • upload_limit – 上传速度限制 bytes/second
  • download_limit – 下载速度限制 bytes/second
  • use_auto_torrent_management – 是否自动管理种子
  • is_sequential_download – 是否顺序下载
  • is_first_last_piece_priority – 是否先下载收尾文件块
  • tags – 标签分配 (added in Web API v2.6.2)
  • content_layout – Original, Subfolder, or NoSubfolder to control filesystem structure for content (added in Web API v2.7) 没关注过这个参数
  • ratio_limit – share limit as ratio of upload amt over download amt; e.g. 0.5 or 2.0 (added in Web API v2.8.1) 分享率限制
  • seeding_time_limit – number of minutes to seed torrent (added in Web API v2.8.1) 做种时间限制

三、工作原理


基于上述说明,我们在做跳检工具的时候首先需要有可添加的种子链接或者种子文件,这里不做说明怎么获取的。我们通过硬盘存在的种子文件进行解析,判断种子文件是否存在于保存路径对应的位置下,判断是否加载、是否跳检。

配置文件:config.yml,qb下边的三个信息就是登陆信息,save_path表示电脑硬盘下常用的存储路径,可以自己扩展(基于yaml语法)

qb:
  ip: localhost
  port: 2021
  user: admin
  pwd: 123456
path:
  save_path:
    - W:\电影仓库
    - J:\电影仓库
from yaml import load
try:
    from yaml import CLoader as Loader
except ImportError:
    from yaml import Loader
def load_config():
    data = load(open('./config.yml', 'rb'), Loader=Loader)
    print(data)
load_config()
{'qb': {'port': 2021, 'user': 'admin', 'pwd': 123456}, 'path': {'save_path': ['W:\\电影仓库', 'J:\\电影仓库']}}

通过上述代码我们可以将其转换成为熟悉的字典。接下来我们就需要获取种子文件进行解析了,之前的文章中我有过介绍,就直接搬运过来:

import torrent_parser as tp

torrent_path = r"C:\Users\CL\Desktop\[LemonHD].[266709]Hellbound 2021 S01 Complete 1080p NF WEB-DL H265 HDR DDP5 1 Atmos-LeagueNF.torrent"
data = tp.parse_torrent_file(torrent_path)
print(data)

输出结果:

{
	'announce': 'https://announce.leaguehd.com/announce.php?passkey=xxxxxxxx',
	'comment': '海棠不惜胭脂色,独立蒙蒙细雨中。',
	'created by': '',
	'info': {
		'files': [{
			'length': 5371995103,
			'path': ['Hellbound.S01E01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}, {
			'length': 5877701549,
			'path': ['Hellbound.S01E02.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}, {
			'length': 5860881886,
			'path': ['Hellbound.S01E03.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}, {
			'length': 4504376575,
			'path': ['Hellbound.S01E04.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}, {
			'length': 5948937008,
			'path': ['Hellbound.S01E05.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}, {
			'length': 6522341196,
			'path': ['Hellbound.S01E06.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv']
		}],
		'name': '地狱公使.Hellbound.2021.S01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF',
		'piece length': 4194304,
		'pieces': ['42846d3c0f2444e3b21c4241e93813a236072c01', '07fa7e1e0f6e0e467f8bce3b803220622c7fb710', 'd197e50069e5a873cb7494f13406e76d7e77fd57', '75b4baf85fccb83540d1b25c982bed1f72c16082', 'ea9a2d27f697e6fe505b82d20e9f92d77f2b3dfe', '6f4a880ecf953c11fb0ef0ff45280f165897696a', '3491717797225aefeb25c390f15e51c315964cb0', '4166ffb5871a730046e23e93fd90e91dd12c5cf4', 'd2dabbcd7684adf8c0095a656acb35bdad87f447', '3553ca6dd87cd5853e2a08a6b56f518a8249f55a', 'e60a14aea02b0ac532d159928a4f67de6504f577', '1d46ff71ba9696312c6df4bae5003a64e45a9cb9'],
		'private': 1,
		'source': '[lemonhd.org] LemonHD'
	}
}

另外一个例子:

{
	'announce': 'https://tracker.totheglory.im/xxxxxxxxxxxxxxxx',
	'comment': 'TorrenTGui.ORG',
	'created by': 'qBittorrent v4.3.0.1',
	'creation date': 1637659097,
	'info': {
		'files': [{
			'length': 12165927052,
			'path': ['Titane.2021.1080p.BluRay.x264.DTS-WiKi.mkv']
		}, {
			'length': 77,
			'path': ['Titane.2021.1080p.BluRay.x264.DTS-WiKi.md5']
		}, {
			'length': 4630,
			'path': ['Titane.2021.1080p.BluRay.x264.DTS-WiKi.nfo']
		}, {
			'length': 149495666,
			'path': ['Sample', 'Titane.2021.1080p.BluRay.x264.DTS-WiKi.Sample.mkv']
		}],
		'name': 'Titane.2021.1080p.BluRay.x264.DTS-WiKi',
		'piece length': 2097152,
		'pieces': ['25bca2c62bf5e860e313ae199b13f74dac73eccd', 'e5c491462186cdd12d57cbb0b65c954eac0bd0fe', 'fef56f71ededf949bc9daea4a536c1427435283c', '18989fdd1ed5535a5287379627465652c2fcfc6c', 'c443e881fb1e1a0be03369482fd1cc93df00fb01', '01ce23ed69c156ce641c8059da993e2d36961f66', '94b253320be234a0fbbc14c28e90020ae444f70a', '1b6403bf358c02629c44840c768ca0efcd66d0cd', '7a3a3e14713884de9a825a330b4d955fffbed860', 'cbfe56c328b86a84e9511cf74f437ef8d329fc2a', '60badaec560686ca71490996ef0e958f301664fa'],
		'private': 1,
		'ttg_tag': '8032a74ec22927a5bd6367537eafd87e'
	}
}

我们可以解析出来的东西包括tracker,种子制作时间,制作工具,文件大小及路径,块的数量,以及source和comment字段。

如果通过文件路径组合起来的文件绝对路径,在硬盘中都存在,那么我们就判断这个种子已经下载完毕。

ok,接下来是所有代码。

from qbittorrentapi import Client, LoginFailed
import torrent_parser as tp
from yaml import load
import os
import hashlib
import bencode
try:
    from yaml import CLoader as Loader
except ImportError:
    from yaml import Loader

def get_qb(config):
    # 获取客户端实例
    qb = Client(host='%s:%s'% (config['ip'], config['port']), username=config['user'], password=config['pwd'])

    # 客户端进行登录
    try:
        qb.auth_log_in()
    except LoginFailed as e:
        print(e)

    # 输出客户端信息
    print(f'qBittorrent: {qb.app.version}')
    print(f'qBittorrent Web API: {qb.app.web_api_version}')
    print()
    return qb


# 根据种子路径获取其hash值
def get_hash(filename):
    with open(filename, 'rb') as f:
        torrent_data = f.read()
        metainfo = bencode.bdecode(torrent_data)
        info = metainfo['info']
        return hashlib.sha1(bencode.bencode(info)).hexdigest()


# 加载配置文件
def load_config():
    data = load(open('./config.yml', 'rb'), Loader=Loader)
    return data


# 获取种子文件列表信息
def pars_torrent(path):
    file_paths = []
    data = tp.parse_torrent_file(path)
    info = dict(data['info'])
    if 'files' in info.keys():
        for item in info['files']:
            file_paths.append(info['name'] + '\\' + '\\'.join(item['path']))
    else:
        file_paths.append(info['name'])
    return file_paths

# 主程序入口
if __name__ == '__main__':
    user_info = load_config()
    qb = get_qb(user_info['qb'])
    save_paths = user_info['save_path']
    
    # 输入种子所在目录
    torrents_path = input("请输入种子保存路径>>")
    files = os.listdir(torrents_path)
    
    # 循环处理种子信息
    for file in files:
        if not file.endswith('.torrent'):
            continue
        print("*********************** 当前处理种子文件:%s ***********************" % file)
        torrent_path = os.path.join(torrents_path, file)
        
        # 种子已经存在于客户端,跳过
        hash_value = get_hash(torrent_path)
        torrent = qb.torrents_info(torrent_hashes=hash_value)
        if len(torrent) == 1:
            print("当前种子已经存在于客户端,跳出……")
            continue
        
        # 判断种子文件是否存在于常用的保存路径
        torrent_files = pars_torrent(torrent_path)
        print('种子文件包含%d个文件'%len(torrent_files))
        for save_path in save_paths:
            flag = True
            for torrent_file in torrent_files:
                if not os.path.isfile(os.path.join(save_path, torrent_file)):
                    print('%s 文件不存在,跳出……' % os.path.join(save_path, torrent_file))
                    flag = False
                    break
            if flag == True:
                qb.torrents_add(torrent_files=torrent_path, save_path=save_path, is_skip_checking=True, is_paused=True)
                print('种子检验完毕,保存路径为%s,已经添加!!' % save_path)

运行示例

************ qBittorrent: v4.2.5 ************
************ qBittorrent Web API: 2.5.1 ************

请输入种子保存路径>>C:\Users\CL\Desktop\测试
************ 当前处理种子文件:[HUDBT].The.Canyon.2009.1080p.AMZN.WEB-DL.DD+5.1.H.264-monkee.mkv.torrent ************
当前种子已经存在于客户端,跳出……
************ 当前处理种子文件:[LemonHD].[265642]The Canyon 2009 1080p AMZN WEB-DL DD+5.1 H.264-monkee.torrent ************
当前种子已经存在于客户端,跳出……
************ 当前处理种子文件:[LemonHD].[266709]Hellbound 2021 S01 Complete 1080p NF WEB-DL H265 HDR DDP5 1 Atmos-LeagueNF.torrent ************
种子文件包含6个文件
W:\电影仓库\地狱公使.Hellbound.2021.S01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF\Hellbound.S01E01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv 文件不存在,跳出……
J:\电影仓库\地狱公使.Hellbound.2021.S01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF\Hellbound.S01E01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv 文件不存在,跳出……
G:\PT电影\地狱公使.Hellbound.2021.S01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF\Hellbound.S01E01.1080p.NF.WEB-DL.H265.HDR.DDP5.1.Atmos-LeagueNF.mkv 文件不存在,跳出……
************ 当前处理种子文件:[TTG] Titane.2021.1080p.BluRay.x264.DTS-WiKi.torrent ************
种子文件包含4个文件
W:\电影仓库\Titane.2021.1080p.BluRay.x264.DTS-WiKi\Titane.2021.1080p.BluRay.x264.DTS-WiKi.mkv 文件不存在,跳出……
J:\电影仓库\Titane.2021.1080p.BluRay.x264.DTS-WiKi\Titane.2021.1080p.BluRay.x264.DTS-WiKi.mkv 文件不存在,跳出……
G:\PT电影\Titane.2021.1080p.BluRay.x264.DTS-WiKi\Titane.2021.1080p.BluRay.x264.DTS-WiKi.mkv 文件不存在,跳出……
输入任何字符结束>>

四、打包链接


上述代码已经打包成可执行软件,自行测试服用。

https://cloud.tomorrow505.xyz/index.php/s/PMnF8SfkdpQbg7H

配置config.yml,运行,输入种子所在目录,等待。



本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!