PT 下载从入门到养老篇一:站点介绍及生存指南

本文最后更新于 2021 年 4 月。

介绍

PT (Private Tracker) 是一种基于私有 BT Tracker 服务器的资源传播形式,经授权的用户使用受允许的客户端进行种子制作与下载。相较于传统 BT,PT 站往往采取了严格的邀请制度以及免责制度来规避法律风险,同时要求用户客户端开启传输加密以绕过运营商的检测策略。

许多高清爱好者聚集在 PT 站,发布翻录的蓝光原盘、CD 以及录制的卫星电视讯号;得益于 Netflix、HBO 等高清流媒体在线视频平台的发展,近年也出现了一些 WEB-DL (Download from web)资源。

目前国内使用的 PT 站源码大部分为基于浙江大学 xiazuojie 团队所开发的开源整站项目 NexusPHP,基于 PHP + MySQL + Memcached。

日前,@burpheart 基于上游项目,开发了新版的 NexuxPHP Safe。其修复了一些已知的安全漏洞,并加入了一些增强用户体验的小功能。

国内 PT 站可以划分为两个系别:教育网 PT 站公网 PT 站

教育网 PT 站

北邮人(北京邮电大学)、蒲公英(西北工业大学)、极速之星(北京理工大学)和六维空间(东北大学)为主。

高校校园网提供的 IPv4 网络一般是有计费及限速策略的,由校方向电信、联通、移动、鹏博士等运营商采购带宽并在出口实施自动分流。而为了推广 IPv6 业务,各高校所接入的中国教育网(CERNET)的 IPv6 网络一般是不计费且不限速的,因此组建一个依托于 IPv6 的免费资源分享网络有着很大意义。

一般来说,教育网 PT 站的原创影视资源较少,大部分为转载资源。Coursera、Udacity 等公开课资源(WEB-DL)、考研视频、电子书等内容较多,此外,北邮人等站点还提供一些诸如 Steam 游戏数据备份文件,这样学生就不用担心被几十个 G 的 Steam 游戏更新榨干网费了。

公网 PT 站

传说中国有五大公网 PT 站:HDS、TTG、HDC、CHD、HDR。 后来经过世界版权日风波,HDStar 管理组被捕入狱,剩下的站点也多多少少受到了一些影响,有些直接关闭了,有的则隐没了。

希望考古中国 PT 站历史的朋友可以查看这个帖子:国内外PT站点评。希望考古国际 PT 站的朋友,可以查看这个帖子:PT站点大全。历史比较悠久了,仅供参考。

距离版权日风波已经过去了七八年,现在国内 PT 站又呈现出繁荣景象。一方面国内电视剧集的分级制度迟迟未推出,而 Netflix、HBO、Disney+、Apple TV+ 等境外流媒体业务的订阅费用也居高不下。另一方面,国内百兆、千兆家庭宽带已经覆盖到了三四线城市甚至是县城,养一个 PT 账号的成本已经相当低了。

在此列出几个常见的站点,仅供参考。

用户规范

对于用户,无论是公网 PT 站还是教育网 PT 站,往往都有以下要求:

  1. 上传、下载量:新手考核计划一般为一个月内 >=50GB 的上传下载量。部分教育网 PT 站可能没有新手考核要求。
  2. 分享率(上传量/下载量):PT 站的优质资源离不开各位用户的分享和做种。为了减少吸血鬼用户的影响,几乎所有 PT 站点都会要求用户的风险率超过一定值。除此之外,用户分享率与用户等级相关,如果风险率低于标准会自动回退到较低的用户等级。
  3. 魔力值(Bonus points,即积分,获得于用户赠送、活动奖励或做种):魔力值可以用于兑换站内头衔、更改用户名、消除广告,甚至至博彩小游戏(例如赌球或 24 点,常见于世界杯期间)。
  4. 最小做种时间:为了保障种子活跃度,一些 PT 站严格禁止下完就跑(称为 H&R, Hit and Run)的行为,要求用户至少持续做种一定时间)。摘录一段 OpenCD 的规则作为参考。
    1
    2
    3
    4
    5
    6
    在种子下载完成后,该种子需在 30 天内做种 36 小时,未达到此要求则记一次 H&R
    H&R10 次,即 ban。皇后及以上级别,包括 VIP,计算 HR 次数,但不 ban 号。

    消除已获得的 H&R 的两种方式
    1. 获得 H&R 的种子在 90 天内达到 300 小时做种时间则会自动消除该 H&R
    2. 用魔力值兑换取消 H&R 次数

生存指南

考核期

大部分站点都有邀请考核制度,需要在一个月时间内达成一定的上传量、下载量以及魔力值。部分站点考核由于不计算魔力值的兑换上传量,建议老老实实下载热门种子并做种。

邀请者可以消耗数倍的魔力值来兑换一个无需新手考核的邀请码。被邀请人也可以付费捐赠(几百元不等)来免除新手考核。

考核后

对于一些以影视作品为主的网站,尽可能的下载热门种子,这样能更快的获得上传量。可以使用 BT 客户端的 RSS 订阅功能,实现无人值守下载。
对于以小种为主的 PT 站,如 OpenCD 以及大部分教育网站点,则需要通过下载大量小体积种子并长时间做种以换取魔力值,再使用魔力值兑换上传。

养老期

此时混 PT 只为偶尔下几个资源,而不是那么注重参与了,因此保持一个良好的分享率以备不时之需是很有必要的。

可以通过 SeedBox 例如 FeralHosting 配合 RSS 订阅来实现无人值守下载,也可以自己搭建黑群晖或直接使用群晖 Synology、威联通 QNAP 等成品 NAS 或私人 HTPC 平台。

部分站点可以通过捐赠获得终身 VIP 头衔,从此不再需要担心分享率问题。

注意事项

  • 除非在特定板块,不要在某个 PT 站提到其他 PT 站点的名字。
    有些网站管理员非常介意用户流失,或者与其他站点发生过不愉快的事情,因此会对触犯此条例的用户执行封禁。
  • 尽可能地尊重发布者,不要在评论区发表不积极的意见。
    尊重资源发布者是一种美德。触犯此条例可能会获得警告信或者永久封禁。
  • 遇到技术问题应先使用搜索引擎检索,而不是当伸手党。
    网站管理员一般非常反感小白用户的问题。
  • 不要作弊
    可能会遭受连锁封禁(被多个站点同时封禁)。
  • 不要持有小号(马甲)
    管理员一般会基于以下规则来判断马甲账号
    1. 用户的登录、注册 IP
    2. 用户客户端上报 Tracker 所使用的 IP
    3. 用户名及邮箱的命名规律
    4. 匿名举报
  • 谨慎选择邀请人,不要随意发送邀请。
    部分站点对于违反某些规则的用户会采取连坐措施,封禁整个邀请链。
  • 不要在公共场合发送、索求邀请码,或者提到网站网址和名称。
    这个“传统”已经持续近十年了,某些管理员觉得似乎把头埋到沙子里就什么都不会发生了。

专题文章列表

Intellij IDEA 执行 JUnit 单元测试的正确姿势

  1. 安装 JUnit 插件

    File -> settings -> Plugins -> Browse repositories -> JUnit -> JUnit Generator V2.0,安装后需重启 Intellij IDEA。

  2. 为当前项目添加依赖

    File -> Project Structure -> Libraries,找到 Jetbrain Intellij IDEA 的安装目录下的 lib 文件夹,添加 hamcrest-core-1.3.jarjunit-4.12.jar 以及 junit.jar

  3. 为待测试类添加测试样例

    在待测类中按 ALT + INSERT,选中 JUnit Test

解决 Office 套件多授权冲突

因为使用 KMS 或绑定多用户的原因,Office 界面可能会出现多个授权信息,形成冲突。

  1. 访问 Office 安装目录
  2. 以管理员权限执行指令 cscript ospp.vbs /dstatus 查看当前在册授权
  3. 记录失效 License 的后五位字符
  4. 以管理员权限执行指令 cscript ospp.vbs /unpkey:[Last 5 chars of license] 注销授权

WA 到死原因总结

  1. 警惕使用 n = -n; 进行数值正负转换

数值在内存中是以补码的形式进行存储的,因此 int 的数据范围为 [-2147483648, 2147483647],左右边界不对称。

当题目中声明所有数据均在 int 范围内时,应当警惕使用 n = -n;:如果值恰好为下界 -2147483648,则运算后结果仍为 -2147483648

  1. 警惕对于负数进行取模操作

不同语言中对于除法的实现算法不同,Java 和 C/C++ 中使用 truncate 除法(截断小数部分),Python 中使用 floor 除法(向下取整),因此负数取模的结果也不相同。

为了保证一致性,建议使用 (n + m) % m 的方式进行取模。

p.s. Ceiling 是向上取整。

macOS Mojave on VMware 调节分辨率

问题

基于 VMware Workstation 15 Pro 安装的 macOS Mojave 显示分辨率始终为 1024 x 768,安装 VMware Tools 与 SwitchResX 均未解决问题。

解决方案

打开 Terminal,执行 /Library/Application\ Support/VMware\ Tools/vmware-resolutionSet [width] [height],最大支持 8192 x 8192

由于虚拟机黑苹果最高只支持 128MB 显存,请不要将分辨率调过高,以免卡顿、花屏。

使用 GitLab 进行开发

开始工作

  1. Git – Downloads 下载最新版本的 Git 客户端。

  2. 运行 Git Bash,执行 ssh-keygen -t rsa -C “[your_email]@domain.com” 创建密钥对,得到 id_rsa.pub 公钥文件与 id_rsa 私钥文件。(务必妥善保管

  3. 参考 私人 GitLab 使用方法 中的 “SSH 配置” 章节,将公钥内容添加至自己的 GitLab 账号。

  4. 访问原始项目,点击中央的 fork 按钮,克隆一个分支至自己的账号。

  5. 访问自己刚刚 fork 出的分支,复制页面中间格式为 [email protected]:[username]/[project_name].git 的字符串。

  6. 在本地计算机上找到你想存放本项目的目录,例如 D:\Programs\,在 Git Bash 中执行 cd [绝对路径] 的方式跳转至该目录,例如 cd D:/Programs (注意前后斜杠的变化)。Windows 用户也可以直接打开该文件夹,右键点击空白区域,点击 Git Bash Here,在该文件夹中打开 Git Bash。

  7. 配置 Git 用户名和邮箱

    1
    2
    $ git config –global user.name "username"
    $ git config –global user.email "[email protected]"
  8. 执行 git clone [刚刚复制的字符串],将项目克隆到本地。

  9. 访问本地仓库,执行 git branch -a 浏览分支列表。

  10. 执行 git remote -v 查看 origin 是否为自己的远程仓库

  11. 执行 git remote add upstream [原始项目的 git 地址] 添加原始项目为同步源。

  12. 执行 git remote -v 查看 upstream 是否为原始项目。

  13. 执行 git fetch upstream 同步仓库。

  14. 执行 git checkout master 切换到 master 分支。

  15. 执行 git merge upstream/master 将原始项目的最新更改同步至本地。

  16. 执行 git push origin master 将本地仓库同步至自己的远程仓库。

  17. 执行 git checkout dev 切换到开发分支。

  18. 使用 Eclipse 打开项目,开始开发工作。

  19. 结束工作,执行 git status 查看修改过的文件。

  20. 执行 git diff 或者 git diff [filename] 比对文件改动,做最后检查。

  21. 执行 git commit -m “[注释]” 提交修改到 暂存区

  22. 执行 git push origin dev 将本地的开发分支提交至自己的远程仓库。

  23. 完成一个阶段性任务(程序功能)后,在 GitLab 页面上发起 Pull Request,项目主管将进行 Code Review 并提出修改建议,通过后将合并至主仓库。

注意事项

  1. 请在每天开始工作前将远程仓库的 master 分支同步至本地(在本地的 master 分支中使用 git fetch upstream 然后 merge)。
  2. 请基于最新的 dev 分支进行开发。(同步方法见上方)

开发帮助

QuickSort Dijkstra 3-Way Partitioning

思想

原始的 2-Way 快排在遇到大量重复数据时会退化为 O(n^2),为了解决这个问题,3-Way 快排被提出了。通过将区间分割为“小于”、“等于”和“大于”(基准数)三个部分,获得了趋近 O(nlogn) 的复杂度。不同于 2-Way 快排的是,我们在此选取一个基准数的值,而非一个基准元素。

(小声逼逼:当然为了方便也可以直接改进 2-Way 快排,在每一次基准数归位后遍历全区间元素,将等于基准数的元素交换到基准数旁边,也能获得等价的三个区间。当然,效率相对于 3-Way 快排有所下降,代码实现的复杂度也上升了。)

使用 i 下标表示“小于”区间的上界;使用 q 下标表示“等于”区间的上界;使用 j 下标表示“大于”区间的下界。

  1. 选取一个元素的值作为基准数值
  2. 判断 arr[q]pivot 的关系: 如果小于 pivot,交换 arr[i]arr[q]q 自增,i 自增 如果大于 pivot,交换 arr[j]arr[q]q ** 不变 **,j 自减 如果等于 pivotq 自增
  3. 重复步骤 2,直至 qj 相遇。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static void swap(int arr[], int a, int b)
{
/**
* Due to Java doesn't have reference, we can use XOR to swap the values
*/
if (a != b)
{
arr[a] ^= arr[b];//a = a^b
arr[b] ^= arr[a];//b = b^a^b = a
arr[a] ^= arr[b];//a = a^b^a = b
}
}
public static void quickSort(int f[], int lo, int hi)
{
if (lo >= hi)
return;

int pivot = f[(int)Math.random() % (hi - lo + 1) + lo];//randomize pivot

/**
* i "less" upper bound
* j "more" lower bound
* q "equal" upper bound
*
* ##less## ->i ##equal## ->q ##unknown## j<- ##more##
*/

int i = lo, j = hi, q = lo;

//partition
while (q <= j)
{
if (f[q] < pivot)
swap(f, q, i++);
else if (f[q] > pivot)
swap(f, q--, j--);//the exchanged value need to be check, so we q--
++q;
}
//recursion
quickSort(f, lo, i);//left
quickSort(f, j+1, hi);//right
}

自建 vlmcsd KMS 服务器激活 Windows 及 Office 套件

服务端操作

  1. 找一台吃灰小鸡(本地虚拟机也行)
  2. https://github.com/Wind4/vlmcsd/releases 下载 latest release
  3. tar -xzvf binaries.tar.gz 解压
  4. 运行

客户端操作

激活 Windows

各 KMS 激活密钥见 KMS 客户端安装密钥 | Microsoft Docs

  1. 以 Windows 管理员权限运行命令提示符
  2. 指定 kms 批量激活服务器 slmgr /skms [服务器地址]
  3. 执行激活操作 slmgr /ato
  4. 查看有效期 slmgr /xpr

注意:

1. 仅 VOL 批量许可版本的 Windows 支持 KMS 激活

2. KMS 激活有效期为 180 天(半年),到期系统会自动向 KMS 服务器更新状态。

3. 不可激活旗舰版 Windows 7

4. 手动安装密钥 slmgr /ipk xxxxx-xxxxx-xxxxx-xxxxx

5. Windows 下载见 MSDN 我告诉你

激活 Office

  1. 以 Windows 管理员权限运行命令提示符,进入到 Office 安装目录
  2. cscript ospp.vbs /sethst:[服务器地址]
  3. cscript ospp.vbs /act
  4. cscript ospp.vbs /dstatus

注意:

1. 仅 VOL 批量许可版本的 Office 支持 KMS 激活https://otp.landian.la/en-us/

2. Office 下载见 Office Tool Plus

快速排序简易入门

快速排序

快速排序(Quick Sort)因其 $O(NlogN)$ 的复杂度成为最常见的算法之一,甚至被纳入了 C++ 的标准库作为 std::sort 的一部分与插入排序糅合在一起以实现更优的时间复杂度。

在学习快速排序算法之前,让我们首先回顾最经典的排序算法——冒泡排序:经过 $(N-1)!$ 次比较,以 $O(N!)$ 的复杂度完成排序。由于冒泡排序每次只比对相邻的两个元素,所以排序效率相对比较低。

快速排序的优势在于,应用了分治的思想(有点像二分),通过多次迭代将元素依次归位,最终完成排序。单元操作如下:

  1. 最左端 选取端元素作为基准数
  2. 使用下标 i 从 最右端 开始寻找小于基准数的元素
  3. 使用下标 j 从 最左端 开始寻找大于基准数的元素
  4. 交换满足条件后的 i, j 下标所对应的元素,然后重复过程 2, 3 直至两下标相遇
  5. 将两下标所处元素与基准数交换

经过以上过程后,基准数左侧的元素均小于等于基准数,基准数右侧的元素均大于等于基准数。接着通过迭代的方式,将此时基准数左端区域与右端区域分别进行下一轮排序操作。当区间内只剩下一个元素时,结束当前过程。

注意:

一、快速排序中扫描时 必须从基准数的对面开始

原因:允许交换的前提:

1. 有 arr[r] < arr[L];

2. 有 arr[l] > arr[L]。

如果从左边开始,则在 l 与 r 相遇时可能只满足了 2 但未满足 1,此时基准数 arr[L] 与 arr[l](arr[r])发生交换,导致一个大于基准数的值被放在了最左。

二、基准数归位后就固定了,接下来分治排列 [L, l – 1] 和 [l+1, R] 即可。(此时 r == l)

改进

对于原始的快速排序,由于每次都从固定的一端选取基准数,当遇到有序序列时,可能会导致基准数归位后其余元素都在基准数的某一侧,而另一侧没有元素的情况,最终导致排序性能退化。为了避免这种情况出现,我们需要引入一个随机化操作来打乱有序序列:在当前区间内随机选取一个元素与基准数交换,然后以其作为新的基准数。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#define INF
#define offline
#include "bits/stdc++.h"
using namespace std;

// int arr[] = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
int arr[100010];
int n;
int t;

inline void Swap(int *a, int *b)
{
t = *a;
*a = *b;
*b = t;
}

inline int readint()
{
char c;
bool neg = false;
while((c = getchar()) &lt; '0' || c &gt; '9')
neg = c == '-';//等价于 neg = (c == '-'),因为 == 的优先级更高
int a = c - '0';
while((c = getchar()) &gt;= '0' &amp;&amp; c &lt;= '9')
a = a * 10 + c - '0';
return neg ? -a : a;
}

inline void Out(int n)
{
if (n &lt; 0)
putchar('-'), n = -n;
if (n &gt;= 10)
Out(n / 10);
putchar(n % 10 + '0');
}

inline void quicksort(int L, int R)
{
int l = L;
int r = R;

Swap(&amp;arr[L + ((int)rand() % (R - L))], &amp;arr[L]);
while (l &lt; r)
{
if (arr[r] &lt; arr[L])
{
while (l &lt; r)
{
if (arr[l] &gt; arr[L])
{
Swap(&amp;arr[l], &amp;arr[r]);
break;
}
else
l++;
}
}
r--;
}
Swap(&amp;arr[L], &amp;arr[l]);
if (L &lt; l - 1)
quicksort(L, l - 1);
if (R &gt; r + 1)
quicksort(r + 1, R);
}

int main()
{
//std::ios_base::sync_with_stdio(false);
//std::cin.tie(0);
//srand((unsigned int)(time(NULL)));
// n = 10;
scanf("%d", &amp;n);
for (int i = 0; i &lt; n; ++i)
arr[i] = readint();

quicksort(0, n - 1);

for (int i = 0; i &lt; n - 1; ++i)
{
Out(arr[i]);
putchar(' ');
}
Out(arr[n-1]);
putchar('\n');

return 0;
}