前言

  • 众做周知,像 Emby、Plex、Infuse 这类媒体服务器,对剧集的文件名是有严格要求的。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    疑犯追踪

    ├─Season 1
    │ S01E01.MP4
    │ S01E02.MP4
    │ ...

    └─Season 2
    S02E01.MP4
    S02E02.MP4
    ...
  • 而我们在 PT 站下的种命名方式五花八门,我们做种的时候还不能更改种子的任何内容,所以,硬链接就显得很有必要了。根据我的理解,硬链就是给源文件创建了个快捷方式,我们可以随意更改快捷方式的名称还不影响源文件,且不占用额外的存储资源,只是无法跨盘操作而已。以下是 ChatGPT 对硬链接的解释:

    1. 硬链接(Hard Link)是文件系统中的一种链接方式,它使多个文件名指向同一个文件数据块。在硬链接的概念下,一个文件的数据并不是直接与文件名绑定的,而是与一个称为索引节点(inode)的结构绑定的。硬链接实际上是多个文件名指向同一个 inode,这意味着它们共享同一个文件内容。

      以下是硬链接的一些关键特性:

      1. 同一文件系统内:硬链接只能在同一个文件系统内创建,不能跨文件系统。
      2. 共享数据:硬链接共享同一个数据块,因此无论通过哪个链接修改文件,都会影响所有硬链接。
      3. 删除文件:只有当所有硬链接都被删除时,文件数据才会被真正删除。在此之前,数据仍然保存在磁盘上。
      4. 相同的权限和属性:硬链接拥有相同的权限、所有者和其他文件属性,因为它们指向同一个 inode。

      创建硬链接

      在类 Unix 系统中,可以使用 ln 命令来创建硬链接。例如:

      1
      ln existing_file hard_link_name

      这样,hard_link_name 将成为指向 existing_file 的硬链接。

      示例

      假设我们有一个文件 file1.txt,它的内容是 “Hello, World!”,我们通过以下命令创建一个硬链接:

      1
      ln file1.txt file2.txt

      此时,file1.txtfile2.txt 实际上是指向同一个数据块的两个文件名。你可以通过 ls -l 命令查看它们,发现它们的 inode 号码是相同的。

      1
      ls -li

      输出可能类似于:

      1
      2
      123456 -rw-r--r-- 2 user group 13 Jun 20 12:00 file1.txt
      123456 -rw-r--r-- 2 user group 13 Jun 20 12:00 file2.txt

      这里,123456 是它们共享的 inode 号码。

      总之,硬链接是一种非常有效的文件管理方式,特别是在需要多个文件名指向同一个文件内容的情况下。

硬链工具

为什么选它?

  1. 系统自带的命令 cp -lr 可以快速批量建立硬链接,但是它有以下几个问题:
    1. 硬链建立后,如果硬链接改名,则又会被重复硬链
    2. 没有黑名单、白名单、缓存机制,只能一把梭
    3. 建立后,很难维护源文件和硬链接的关系,比如源文件删除后,很难找到硬链接的位置
  2. 特有优势:
    1. 有 GUI:无需再每次登录到 NAS 机器进行命令输入了
    2. 重复检测hlink 重复检测是通过文件的 inode 号来进行检测,大家可以通过 ls -i 查看文件的 inode。只要文件内容没有改变,则 inode 不会改变,刚好对应各种电影、动漫、电视剧视频文件的内容肯定是不会变更的,所以硬链接后则内容不会改变,那么 inode 不会改变,便可用于重复检测
    3. 黑白名单机制:如何过滤非视频文件,则可用黑白名单来进行管控需要硬链的文件,这样保证 PT种子 内部的文本文件不会被硬链过去,持续保种
    4. 缓存机制:部分视频文件观看后,需要删除。但是不希望下次继续硬链过来,则可以打开缓存,再下次硬链时自动排除这些缓存的文件
    5. 更友好的提示:硬链过程中,会有 进度提示,失败后会有 错误提示
    6. 同步机制:硬链创建后,可以通过 hlink prune 来同步源文件和硬链文件,更简单的管理它们,更详细的使用见 hlink prune 介绍

安装

以下只介绍 Docker 方式,其余请参考官方 Wiki

  • Docker CLI:

    1
    2
    3
    4
    5
    6
    7
    8
    docker run -d --name hlink \
    -e PUID=$YOUR_USER_ID \
    -e PGID=$YOUR_GROUP_ID \
    -e UMASK=$YOUR_UMASK \
    -e HLINK_HOME=/data \
    -p 9090:9090 \
    -v $YOUR_NAS_VOLUME_PATH:/data \
    likun7981/hlink:latest
  • Docker Compose:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    version: '2'

    services:
    docker:
    image: likun7981/hlink:latest
    restart: on-failure
    ports:
    - 9090:9090
    volumes:
    - $YOUR_NAS_VOLUME_PATH:/data
    environment:
    - PUID=$YOUR_USER_ID
    - PGID=$YOUR_GROUP_ID
    - UMASK=$YOUR_UMASK
    - HLINK_HOME=/data

    在类Unix系统(如Linux、macOS)中,可以使用以下命令来查看进程的用户ID(PUID)、组ID(PGID)和文件创建掩码(umask)。

    查看PUID和PGID

    1. 查看当前进程的用户ID和组ID

      • 可以使用id命令:
        1
        id
        这将显示当前用户的用户ID(UID)和组ID(GID)。
    2. 查看特定进程的用户ID和组ID

      • 可以使用ps命令并配合适当的选项:
        1
        ps -o uid,gid,pid,comm -p <PID>
        这里,<PID>是你想查看的进程ID。

    查看umask

    1. 查看当前shell的umask

      • 直接输入以下命令:
        1
        umask
        这将显示当前shell会话的umask值。
    2. 查看特定进程的umask

      • 查看特定进程的umask比较复杂,因为umask值通常不会直接显示在/proc文件系统中。但是你可以通过查看进程的启动脚本或配置文件来间接了解它们的umask。

    示例

    假设你想查看当前用户的UID、GID和umask,可以这样做:

    1
    2
    3
    4
    5
    # 查看UID和GID
    id

    # 查看umask
    umask

    假设你有一个进程ID为1234的进程,想查看该进程的UID和GID:

    1
    2
    # 查看进程1234的UID和GID
    ps -o uid,gid,pid,comm -p 1234

配置

  1. 通过 <宿主机IP>:9090 访问 GUI

  2. 点击右下角的创建配置image名称随意,具体的配置解析如下:

    • pathsMapping 是填写硬链源路径和目标路径的参数

      1. 例如我的剧存在 /home/liqiye/videos,我想给它硬链到 /home/liqiye/links 里,而我在创建 Docker 容器的时候填了 -v /home/liqiye:/pt 的话,这里就该填

        1
        2
        3
        pathsMapping: {
        '/pt/videos': '/pt/links'
        }
      2. 假如我的剧存在 /home/liqiye/videos,我想给它硬链到 /home/yeqili/links 里,那我在创建 Docker 容器的时候

        • 要么把整个 home 文件夹映射进去:-v /home:/pt,然后填入

          1
          2
          3
          pathsMapping: {
          '/pt/liqiye/videos': '/pt/yeqili/links'
          }
        • 要么将 liqiyeyeqili 两个文件夹分别映射: -v /home/liqiye:/pt1 -v /home/yeqili:/pt2,然后填入

          1
          2
          3
          pathsMapping: {
          '/pt1/videos': '/pt2/links'
          }

          当然,直接映射 /videoslinks 也是可以的

    • includeexclude 我一般空着,这样就把整个文件夹全部硬链过去

    • 剩下的我都是默认的,自己看看下面的注释就行,如果想重新硬链,右上角编辑缓存把缓存删掉即可(注意段位的逗号)image

  3. 点击右上角的创建任务image名称随意,配置文件就选刚才添加的,然后点确定image

  1. 先去 hlink 的 GUI 找到刚才添加的任务复制脚本image

  2. 去到 QB / TR 的目录下,以 Docker 为例吧

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 找到 QB / TR 的 CONTAINER ID
    docker ps

    # 进入容器
    docker exec -it <CONTAINER ID> bash

    # 找到映射的配置文件路径,一般是 /config
    cd /config

    # 创建一个 shell 脚本
    vi hlink.sh

    内容如下:

    1
    2
    3
    4
    5
    6
    7
    #!/bin/bash

    # 定义URL
    url="<刚才在 hlink GUI 复制的脚本>"

    # 使用curl执行请求,不输出任何结果
    curl -s -o /dev/null "$url"

    按 ESC,输入 :wq 回车保存退出,顺便给个执行权限

    1
    chmod +x hlink.sh
  3. 我们来到 QB / TR 的 GUI

    • QB 的话来到下载,拉到最下面,勾选 torrent 完成时运行外部程序,然后在里面填入 bash /config/hlink.sh "%F",最后点保存image
    • TR 的话来到左上角的参数,基本设置,勾选 种子下载完成后执行以下脚本,再填入 /config/hlink.sh,最后点保存
      image

结语

到此,种子下载完会自动硬链到我们指定的位置,修改一下文件的命名,就可以愉快的刮削啦~