Libtorrent - Given a magnet link, how do you generate a torrent file?
Asked Answered
S

4

20

I have read through the manual and I cannot find the answer. Given a magnet link I would like to generate a torrent file so that it can be loaded on the next startup to avoid redownloading the metadata. I have tried the fast resume feature, but I still have to fetch meta data when I do it and that can take quite a bit of time. Examples that I have seen are for creating torrent files for a new torrent, where as I would like to create one matching a magnet uri.

Swallowtail answered 31/12, 2011 at 18:29 Comment(1)
Granted, the documentation is horrendous (though strangely usable). But, what's wrong with the metadata extension rasterbar.com/products/libtorrent/manual.html#add-extension ?Magill
B
13

Solution found here:

http://code.google.com/p/libtorrent/issues/detail?id=165#c5

See creating torrent:

http://www.rasterbar.com/products/libtorrent/make_torrent.html

Modify first lines:

file_storage fs;

// recursively adds files in directories
add_files(fs, "./my_torrent");

create_torrent t(fs);

To this:

torrent_info ti = handle.get_torrent_info()

create_torrent t(ti)

"handle" is from here:

torrent_handle add_magnet_uri(session& ses, std::string const& uri add_torrent_params p);

Also before creating torrent you have to make sure that metadata has been downloaded, do this by calling handle.has_metadata().

UPDATE

Seems like libtorrent python api is missing some of important c++ api that is required to create torrent from magnets, the example above won't work in python cause create_torrent python class does not accept torrent_info as parameter (c++ has it available).

So I tried it another way, but also encountered a brick wall that makes it impossible, here is the code:

if handle.has_metadata():

    torinfo = handle.get_torrent_info()

    fs = libtorrent.file_storage()
    for file in torinfo.files():
        fs.add_file(file)

    torfile = libtorrent.create_torrent(fs)
    torfile.set_comment(torinfo.comment())
    torfile.set_creator(torinfo.creator())

    for i in xrange(0, torinfo.num_pieces()):
        hash = torinfo.hash_for_piece(i)
        torfile.set_hash(i, hash)

    for url_seed in torinfo.url_seeds():
        torfile.add_url_seed(url_seed)

    for http_seed in torinfo.http_seeds():
        torfile.add_http_seed(http_seed)

    for node in torinfo.nodes():
        torfile.add_node(node)

    for tracker in torinfo.trackers():
        torfile.add_tracker(tracker)

    torfile.set_priv(torinfo.priv())

    f = open(magnet_torrent, "wb")
    f.write(libtorrent.bencode(torfile.generate()))
    f.close()

There is an error thrown on this line:

torfile.set_hash(i, hash)

It expects hash to be const char* but torrent_info.hash_for_piece(int) returns class big_number which has no api to convert it back to const char*.

When I find some time I will report this missing api bug to libtorrent developers, as currently it is impossible to create a .torrent file from a magnet uri when using python bindings.

torrent_info.orig_files() is also missing in python bindings, I'm not sure whether torrent_info.files() is sufficient.

UPDATE 2

I've created an issue on this, see it here: http://code.google.com/p/libtorrent/issues/detail?id=294

Star it so they fix it fast.

UPDATE 3

It is fixed now, there is a 0.16.0 release. Binaries for windows are also available.

Blunt answered 5/3, 2012 at 7:52 Comment(0)
W
6

Just wanted to provide a quick update using the modern libtorrent Python package: libtorrent now has the parse_magnet_uri method which you can use to generate a torrent handle:

import libtorrent, os, time

def magnet_to_torrent(magnet_uri, dst):
    """
    Args:
        magnet_uri (str): magnet link to convert to torrent file
        dst (str): path to the destination folder where the torrent will be saved
    """
    # Parse magnet URI parameters
    params = libtorrent.parse_magnet_uri(magnet_uri)
    params.save_path = "."

    # Download torrent info
    session = libtorrent.session()
    handle = session.add_torrent(params)
    print "Downloading metadata..."
    while not handle.has_metadata():
        time.sleep(0.1)

    # Create torrent and save to file
    torrent_info = handle.get_torrent_info()
    torrent_file = libtorrent.create_torrent(torrent_info)
    torrent_path = os.path.join(dst, torrent_info.name() + ".torrent")
    with open(torrent_path, "wb") as f:
        f.write(libtorrent.bencode(torrent_file.generate()))
    print "Torrent saved to %s" % torrent_path
Willumsen answered 29/9, 2014 at 14:34 Comment(0)
A
0

If saving the resume data didn't work for you, you are able to generate a new torrent file using the information from the existing connection.

fs = libtorrent.file_storage()
libtorrent.add_files(fs, "somefiles")
t = libtorrent.create_torrent(fs)
t.add_tracker("http://10.0.0.1:312/announce")
t.set_creator("My Torrent")
t.set_comment("Some comments")
t.set_priv(True)
libtorrent.set_piece_hashes(t, "C:\\", lambda x: 0),  libtorrent.bencode(t.generate())
f=open("mytorrent.torrent", "wb")
f.write(libtorrent.bencode(t.generate()))
f.close()

I doubt that it'll make the resume faster than the function built specifically for this purpose.

Absolutely answered 26/1, 2012 at 11:24 Comment(0)
S
0

Try to see this code http://code.google.com/p/libtorrent/issues/attachmentText?id=165&aid=-5595452662388837431&name=java_client.cpp&token=km_XkD5NBdXitTaBwtCir8bN-1U%3A1327784186190 it uses add_magnet_uri which I think is what you need

Softspoken answered 28/1, 2012 at 21:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.