You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Java从Magnet链接生成Torrent文件?技术实现咨询

把Magnet URI转成.torrent文件的Java实现方案

嘿,我之前刚好搞定过类似的需求——在Java里把Magnet URI转换成.torrent文件。既然你已经解析了目标Magnet的内容(info hash、文件名、tracker列表都拿到了),下面给你两个可行的实现思路:

一、用第三方库快速实现(最省心)

首推jlibtorrent,它是libtorrent的Java绑定,功能很完善,直接支持从Magnet生成torrent文件,还能处理元数据缺失的情况。

步骤1:引入依赖

如果用Maven,把这段加到你的pom.xml里:

<dependency>
    <groupId>com.frostwire</groupId>
    <artifactId>jlibtorrent</artifactId>
    <version>1.2.18-RC1</version>
</dependency>

步骤2:编写核心代码

结合你解析的Magnet URI,代码可以这么写:

import com.frostwire.jlibtorrent.*;
import java.io.File;
import java.io.IOException;

public class MagnetToTorrentConverter {
    public static void main(String[] args) throws IOException {
        // 你提供的Magnet URI
        String magnetUri = "magnet:?xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36&dn=Leaves+of+Grass+by+Walt+Whitman.epub&tr=udp%3A%2F%2Ftracker.example4.com%3A80&tr=udp%3A%2F%2Ftracker.example5.com%3A80&tr=udp%3A%2F%2Ftracker.example3.com%3A6969&tr=udp%3A%2F%2Ftracker.example2.com%3A80&tr=udp%3A%2F%2Ftracker.example1.com%3A80";
        
        // 初始化libtorrent会话
        SessionParams sessionParams = new SessionParams();
        Session session = new Session(sessionParams);
        
        // 解析Magnet URI为添加种子的参数
        AddTorrentParams addParams = AddTorrentParams.parseMagnetUri(magnetUri);
        
        // 设置输出的torrent文件路径
        File outputTorrent = new File("LeavesOfGrass.torrent");
        
        // 尝试生成torrent文件
        TorrentInfo torrentInfo = addParams.getTorrentInfo();
        if (torrentInfo != null) {
            // 元数据完整,直接保存
            torrentInfo.saveTorrent(outputTorrent);
            System.out.println("Torrent文件已生成:" + outputTorrent.getAbsolutePath());
        } else {
            // 元数据缺失(有些Magnet只带info hash和tracker),需要监听元数据获取事件
            System.out.println("当前Magnet缺少完整元数据,需要连接tracker/DHT获取后再生成文件");
            // 这里可以添加监听器,等待metadata_received事件触发后再保存
            session.addListener(new TorrentAlertAdapter() {
                @Override
                public void metadataReceived(MetadataReceivedAlert alert) {
                    try {
                        alert.getTorrentInfo().saveTorrent(outputTorrent);
                        System.out.println("元数据获取完成,Torrent文件已生成");
                        session.stop();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            // 保持会话运行直到获取元数据
            try {
                Thread.sleep(30000); // 等待30秒,实际场景可以用更优雅的等待逻辑
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        session.stop();
    }
}

划重点:很多Magnet URI只包含info hash和tracker,没有文件分片哈希(pieces)这类核心元数据,这时候必须通过tracker或DHT网络拿到完整元数据才能生成有效的torrent文件,上面的代码已经处理了这种情况。

二、手动实现(适合深入理解torrent结构)

如果你不想依赖第三方库,可以自己构建Bencode格式的torrent文件(torrent本质是Bencode编码的字典),不过这个方法需要处理元数据获取的问题,相对麻烦。

核心步骤:

  1. 了解torrent的Bencode结构
    一个标准torrent文件的核心结构是:

    • announce: 主tracker地址
    • announce-list: 所有tracker的列表(二维数组格式)
    • info: 包含文件信息的字典,它的SHA-1哈希就是Magnet里的btih值,里面必须有name(文件名)、piece length(分片大小,一般设256KB)、pieces(所有分片的SHA-1哈希拼接成的字节数组)
  2. 填充你解析的Magnet数据
    把你拿到的文件名、tracker列表填入字典,但是pieces数据需要从网络获取(Magnet本身不提供),这部分是手动实现的难点。

  3. 实现Bencode编码
    你可以自己写一个简单的Bencode编码器,或者用轻量的工具类来完成编码,最后把编码后的字节写入文件。

示例代码框架(假设已经有Bencode工具类):

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ManualMagnetConverter {
    public static void main(String[] args) throws IOException {
        // 你解析后的Magnet数据
        String infoHashHex = "d2474e86c95b19b8bcfdb92bc12c9d44667cfa36";
        String fileName = "Leaves of Grass by Walt Whitman.epub";
        List<String> trackers = List.of(
                "udp://tracker.example4.com:80",
                "udp://tracker.example5.com:80",
                "udp://tracker.example3.com:6969",
                "udp://tracker.example2.com:80",
                "udp://tracker.example1.com:80"
        );
        
        // 构建torrent字典
        Map<String, Object> torrentDict = new HashMap<>();
        // 设置主tracker
        torrentDict.put("announce", trackers.get(0));
        
        // 构建announce-list(Bencode要求是二维列表)
        List<List<String>> announceList = new ArrayList<>();
        for (String tracker : trackers) {
            List<String> singleTracker = new ArrayList<>();
            singleTracker.add(tracker);
            announceList.add(singleTracker);
        }
        torrentDict.put("announce-list", announceList);
        
        // 构建info字典(注意:缺少pieces数据的话,这个torrent文件无效)
        Map<String, Object> infoDict = new HashMap<>();
        infoDict.put("name", fileName);
        infoDict.put("piece length", 262144); // 256KB的分片大小
        // TODO: 这里需要添加pieces字节数组,必须从网络获取元数据才能得到
        
        torrentDict.put("info", infoDict);
        
        // 编码并写入文件
        byte[] bencodedData = BencodeUtils.encode(torrentDict); // 假设BencodeUtils是你的编码工具类
        try (FileOutputStream fos = new FileOutputStream("manual_leaves.torrent")) {
            fos.write(bencodedData);
            System.out.println("手动生成的torrent文件已保存(注意:如果缺少pieces则文件无效)");
        }
    }
}

提醒:手动实现最大的问题是获取pieces数据,这需要你自己实现tracker/DHT交互逻辑来拉取元数据,工作量不小,所以如果不是为了学习,优先用第一种方案。


内容的提问来源于stack exchange,提问作者Tarek Mohamed

火山引擎 最新活动