浅谈PT站自动发种

Rhilip 2018-04-01 PM 8869℃ 1条

最近写Autoseed的人真多,我就抛砖引玉的讲讲Python的实现吧。但是其实并不是只有Python才能实现,只要该语言具有网络通信以及本地文件读写的能力均可以。(比如某人的就是用Node.js)

传统发种流程

在介绍Autoseed的流程前,我们先回顾下传统的发种流程。。

传统发种流程.png

可以看到,我们需要先要在本地存在你想要自动发布的文件,并准备好发种表单需要的信息。完成发布后需要下载对应种子,以及做种软件中正确做种即可。

所以我们的自动发种程序只要模拟这个过程即可了~ (是吧是吧,多简单

序言

本来在PT站发种就不是一件简单的事,想要自动发种就更存在问题了。比如,

  1. 种子资源从那里获取?(上游PT站点、BT网络,自抓取);如果种子资源不是自抓取的,那么使用什么方法获取?(flexget,irssi-autodl;torrent文件还是magnet连接)
  2. 简介如何生成?(数据库、自引用)
  3. 发种表单中那些是需要根据转发种子信息修改的?(季度信息,副标题)
  4. 如果将表单模拟发送到站点?又使用什么方法向bt做种软件添加新种子?(watch-dir,rpc,web-api)

如果你都有点思路了,欢迎看下本人已有的开源实现 Rhilip/Pt-Autoseed。(广告:欢迎watch、star、fork、pr)
额(⊙﹏⊙) ,如果不能一下子看懂的话,可以看下最早的一次commits 6b4fb88/autoseed.py至少那时候还稚嫩,而且单文件的逻辑比较好理清。

其他实现: https://github.com/rachpt/AutoSeed

后面我会以 Ubuntu + Python3 + Transmission 环境介绍整个过程。

种子资源从那里获取?

自抓取

如何自抓取资源不再本文的讨论范围,但是如果是自抓取来源的话,如何制作/修改种子文件应该是首先要考虑的问题。特别是对于某些0day解压包的情况。

Linux平台上比较有名的制作种子的工具是mktorrent,使用sudo apt-get install mktorrent即可安装,之后就可以用Python的subprocess库,或者os.system来调用。如下是在Shell下使用mktorrent生成种子的命令:

mktorrent -v -p -a http://tracker.url -o filename.torrent folder_name

当然,也有封装好的python-mktorrent库,仔细找找就行~

注意以下几点就行了:

  1. 多数NexusPHP站点不支持无Tracker项的种子,所以一定要添加一个任意的Tracker地址项。
  2. 种子名(-o 后第一项)中可以不添加 .torrent,如果没有,会自动添加的。
  3. 种子名和目录名中如果有空格字符,请使用双引号""包裹。目录名这里如果填入的是具体文件,则会对单一文件做种。

Flexget

超级成熟的RSS订阅软件。而且支持watch、transmission-rpc等多种添加方法。在这里就不献丑了。我就说下订阅列表处理的问题。(因为有人问过)

如果是国外站点订阅欧美剧集,可以使用series模块,配合qualitiesset项可以对剧集质量进行筛选。此外需要注意的是,series模块默认是不下载season pack的,需要额外添加season_packs: yes项才可以。

如果是其他类型站点订阅,个人比较建议使用RSS链接获取全部链接(而不是使用某些RSS源提供的search方法),再使用Regexp模块进行正则筛选。

参考配置示例:Rhilip/config.yml at The Reseed List - GithubGist

此外请注意,使用Flexget接受magnet链接并通过transmissionrpc方式向transmission添加种子的方式,会使得生成的种子文件中缺少tracker项,部分站点无法正确上传。

2019.02.25注 你可以考虑对magent生成的种子文件进行修改来实现一颗带有空announce项的种子。

irssi-autodl

irssi-autodl 一般会配合rtorrent来操作(虽然不是必须的),如果要使用其他软件进行下载操作则使用watch目录进行操作(设置Action行为为Save to watch Folder.)。

简介如何生成

种子简介一般是较为重要的一环,解决方法主要是数据库存储、引用(自引用、他站引用)及自生成。

数据库存储

对于发种表单较为简单的站点,如果发种类别较为单一,使用数据库简单管理较为方便。如本人第一版就是使用数据库对发种表单所有的信息以数据库形式存储(参见Pt-Autoseed/sql/tv_info.data_only.sql

另外对于某些站点,直接搜索较为麻烦,比如六维空间(6V,非NexusPHP构架站点)搜索界面启用了csrf认证(已一个隐藏的input的hash值)。你需要先获取该值,然后构造搜索字典使用post方法提交,此外该站点限制了搜索间隔(30s)。搜索较为麻烦。

6v_search_csrf.jpg

经过几次重构,本人目前已经转用自引用方式生成简介信息。但是在数据库及相关发种逻辑中保留了数据库存储的方法。但是因为需要面对多站发布的情况。目前存储的已经不是实际的发种表单信息,而是各站的“参考”引用种子号。同时可以对各站不需要发布的种子进行-1标记。

table_info_list.jpg

自引用

通过搜索对应种子在目标站点可以供引用的种子信息,可以从已有种子的信息中分析得到可供发种表单使用的信息。目前本人就采用这种方法。
部分站点提供API形式的自引用接口,如西农麦田pt站点的对应的接口网址为:https://pt.nwsuaf6.edu.cn/citetorrent.php?torrent_id={tid} ,所有发种表单信息均可从中得到。

nwsuaf6_clone_api.jpg

对于部分不提供API的站点,也可以采取读取/details.php?id={tid}页面进行分析,如果发种表单为bbcode格式,因为NexusPHP系对于bbcodeparser的处理较为简单,可直接使用html2bbcode库将原有简介信息转化为bbcode格式。如下示例代码。

import requests
from bs4 import BeautifulSoup
from html2bbcode.parser import HTML2BBCode

parser = HTML2BBCode()  # 实例化parser

r = requests.get("https://nexusphp.url", cookies=site_cookies)  # 使用Cookies作为身份认证
b = BeautifulSoup(r.text,"lxml")  # 用BeautifulSoup库解析网页
descr_tag = b.find("div",id="kdescr")  # 获取原始简介tag信息
descr_html = str(descr_tag)  # 将tag信息转成string文本
descr_ubb = str(parser.feed(descr_html))  # HTML2BBCode

自生成

这一块不是指根据种子内容修改简介,而是指直接“凭空”生成所有简介信息。同时这一块仅作抛砖引玉,不排除有其他方法。(因为我自己都没用过。。。。

下面介绍两种已经较为成熟的实现

  • 使用种子文件名的关键信息(如剧名、季度)通过豆瓣API、Bangumi公开API的搜索功能搜索出相应的douban、Bangumi号,然后(使用movieinfogen等工具)生成对应简介

movieinfo_through_douban.jpg

  • 参考代码:
import requests

search_name = "Young.Sheldon.S01"

douban_search_api_url = "https://api.douban.com/v2/movie/search?q={}"
bangumi_search_api_url = "https://api.bgm.tv/search/subject/{}?responseGroup=large&max_results=20&start=0"
ptgen_api_url = "https://api.rhilip.info/tool/movieinfo/gen"

douban_api_search = requests.get(douban_search_api_url.format(search_name))
douban_api_json = douban_api_search.json()

douban_alt_list = list(map(lambda d:{"alt":d["alt"], "title":d["title"]}, douban_api_json["subjects"]))  # 此处读取了api中的subjects项,并从该列表中获取了alt和title项。

douban_alt = douban_alt_list[0]["alt"]  # 此处假定第一项即是我们需要的信息

# 使用Pt-Gen生成对应信息(具体文档参见 https://github.com/Rhilip/PT-help/blob/master/modules/infogen/README.md)
ptgen_api = requests.get(ptgen_api_url, params={"url": douban_alt})
ptgen_api_json = ptgen_api.json()

descr = ptgen_api_json["format"]  # 这就是我们需要的简介信息
  • 根据种子的hash值从mikanani.me获取种子对应的Bangumi链接,然后根据Bangumi信息生成对应简介。(仅适用于动漫转化原种)

    • 参考示例: BYRBT Bangumi Info
    • Python实现示例截图:
      torrent_hash_through_mikanani_bgm.jpg
    • 参考代码(此处假设对应hash及bgm链接均存在,不存在的情况请参照js实现做异常判断):
import re
import requests

torrent_hash = "e4c64aea419db6d4e35c37275c961e6bb13cf58f"  # [JYFanSub][Dagashi_Kashi_2][12][GB_CN][HEVC][720p].mp4 ,  可以从BT软件中获取或者使用相关python库解析torrent文件获得

mikanani_page_url = "https://mikanani.me/Home/Episode/{}"
ptgen_api_url = "https://api.rhilip.info/tool/movieinfo/gen"

mikanani_hash_page = requests.get(mikanani_page_url.format(torrent_hash))
mikanani_bangumi_suffix = re.search("href=\"(/Home/Bangumi/[\d#]+)",mikanani_hash_page.text).group(1)
mikanani_bangumi_page = requests.get("https://mikanani.me" + mikanani_bangumi_suffix)
bgm_alt = re.search("https?://bgm.tv/subject/\d+",mikanani_bangumi_page.text).group(0)

ptgen_api = requests.get(ptgen_api_url, params={"url": bgm_alt})
ptgen_api_json = ptgen_api.json()

descr = ptgen_api_json["format"]  # 这就是我们需要的简介信息

发种更新简介

老种子的简介并不一定能完全使用,特别是使用自引用的方式获得简介。需要进行一些处理,删除原种子的Mediainfo信息、提示信息等,并更新原有的季度信息。

各站的处理机制均不相同,比如本人已经的实现中,BYRBT等分割原有标题信息,并在新字典中对该信息进行更新即可;而NPUPT等可能需要使用re.sub()str.replace()等进行替换。又比如说HUDBT等站点对种子主标题有要求,不需要"."来分割等。应因地适宜滴配置相关处理流程。

所以本处就介绍些通用的方法 (偷懒~~

import os
import re
import subprocess

file = "/dir/to/movie.mkv"

process = subprocess.Popen(["mediainfo", file], stdout=subprocess.PIPE)
output, error = process.communicate()
if not error and output != b"\n":
    output = output.decode()  # bytes -> string
    output = re.sub(re.escape(file), os.path.basename(file), output)  # Hide file path
else:
    output = ""
import os

file = "/dir/to/movie.mkv"
img_file_loc = "/dir/to/movie.jpg"
baseCommand = "ffmpeg -ss 00:10:10 -y -i '{file}' -vframes 1 '{thu_loc}' >> /dev/null 2>&1"
ffmpeg_sh = baseCommand.format(file=file, thu_loc=img_file_loc)
stderr = os.system(ffmpeg_sh)

发布种子

请常备: Requests 文档 — 高级用法 — POST 多个分块编码的文件

我们这里使用Requests库模拟表单提交。

可以使用专业抓包工具如Fiddler获取发布数据包,当然Chrome等浏览器提供的开发者工具基本足够了。首先准备好一个已经在该站发布过的种子(直接下载一个),并填写好相关表单。
takeupload_before.jpg

打开开发者面板,勾选Network项中的Preserve Log以防止页面跳转导致的记录丢失,然后点击发布。一般会提示上传失败。不过不用担心,实际的交互信息已经被记录了。
takeupload_send.jpg

剩下的只要将这些改成Python-Requests库模拟的相关格式就行了。我这里就偷懒直接用最早的模板了。

2019.02.25注:此处代码已经无法使用,详见发种姬修复之 "请填写必填项目上传失败!"


import requests

multipart_data = (
    ("type", ('', str(401))),
    ("second_type", ('', str(15))),
    ("file", (torrent_name, open(torrentFile, 'rb'), 'application/x-bittorrent')),
    ("tv_type", ('', "大陆")),
    ("cname", ('', "中文名")),
    ("tv_ename", ('', "英文名")),
    ("tv_season", ('', "剧集季度信息")),
    ("tv_filetype", ('', "剧集文件格式")),
    ("type", ('', str(401))),
    ("small_descr", ('', "副标题")),
    ("url", ('', "IMDb链接")),
    ("dburl", ('', "豆瓣链接")),
    ("nfo", ('', "")),
    ("descr", ('', "简介")),
    ("uplver", ('', "yes")),
)
post = requests.post(url="http://nexusphp.site/takeupload.php", cookies=cookies, files=multipart_data)

一般如果发布成功的话,会做页面跳转。通过检查页面链接是否改变(跳转)或者页面提示来确定是否发布成功。

添加种子

  • 设定BT软件的watch-dir,然后将发布后种子下载到该监控目录。BT软件会自动读取并添加该种子
import requests
import os

download_torrent_link = "http://download.rhilip.info/t.torrent"
download_torrent_set = "/dir/to/watch/t.torrent"
torrent_file = requests.get(download_torrent_link, cookies=cookies)
with open(download_torrent_set + ".get", "wb") as code:
    code.write(torrent_file.content)
    os.rename(download_torrent_set + ".get", download_torrent_set)
  • 通过BT软件的WEB-PRC方法(以Transmission为例)
import transmissionrpc

download_torrent_link = "http://download.rhilip.info/t.torrent"
tc = transmissionrpc.Client(address, port, user, password)
tc.add_torrent(torrent=download_torrent_link)
标签: PT, Python, Autoseed

非特殊说明,本博所有文章均为博主原创。

评论啦~



唉呀 ~ 仅有一条评论


  1. toulanboy
    toulanboy

    R酱太强了。学习了。

    回复 2018-05-05 09:07