Search code examples
hyperlinkbittorrent

Generate torrent links from server-side


I don't know a lot about torrents, at least not enough to understand how certain websites can offer both a normal download link and a torrent link to download a file uploaded by a user.

Is generating a torrent link something common and simple to achieve. Would I need a server installation?

I've made an ugly C# implementation from a Java source, and to make sure some of my encoded variables were correct, I used NBEncode from Lars Warholm.

    // There are 'args' because I'm using it from command-line. (arg0 is an option not used here)
    // Source file
    args[1] = Directory.GetCurrentDirectory() + args[1];
    // Name to give to the torrent file
    args[2] = Directory.GetCurrentDirectory() + args[2];

    var inFileStream = new FileStream(args[1], FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    var filename = args[2];

    //BEncoding with NBEencode
    var transform = new BObjectTransform();
    MemoryStream s = new MemoryStream();
    OSS.NBEncode.Entities.BDictionary bod = new OSS.NBEncode.Entities.BDictionary();
    OSS.NBEncode.Entities.BDictionary meta = new OSS.NBEncode.Entities.BDictionary();

    // Preparing the first part of the file by creating BEncoded objects
    string announceURL = "https://www.mysite.com/announce";
    int pieceLength = 512 * 1024;
    bod.Value.Add(new BByteString("name"), new OSS.NBEncode.Entities.BByteString(filename));
    bod.Value.Add(new BByteString("length"), new OSS.NBEncode.Entities.BInteger(inFileStream.Length));
    bod.Value.Add(new BByteString("piece length"), new OSS.NBEncode.Entities.BInteger(pieceLength));
    bod.Value.Add(new BByteString("pieces"), new BByteString(""));
    meta.Value.Add(new BByteString("announce"), new BByteString(announceURL));
    meta.Value.Add(new BByteString("info"), bod);
    byte[] pieces = hashPieces(args[1], pieceLength);
    transform.EncodeObject(meta, s);
    s.Close();

    // Notice that we finish with a dictionary entry of "pieces" with an empty string.
    byte[] trs = s.ToArray();
    s.Close();
    inFileStream.Close();

    // I don't know how to write array of bytes using NBEncode library, so let's continue manually

    // All data has been written a MemoryStreamp, except the byte array with the hash info about each parts of the file

    Stream st = new FileStream(filename + ".torrent", FileMode.Create);
    BinaryWriter bw = new BinaryWriter(st);

    // Let's write these Bencoded variables to the torrent file:
    // The -4 is there to skip the current end of the file created by NBEncode

    for (int i = 0; i < trs.Length - 4; i++)
    {
        bw.BaseStream.WriteByte(trs[i]);
    }

    // We'll add the length of the pieces SHA1 hashes:
    var bt = stringToBytes(pieces.Length.ToString() + ":");

    // Then we'll close the Bencoded dictionary with 'ee'
    var bu = stringToBytes("ee");

    // Let's append this to the end of the file.
    foreach (byte b in bt)
    {
        bw.BaseStream.WriteByte(b);
    }
    foreach (byte b in pieces)
    {
        bw.BaseStream.WriteByte(b);
    }
    foreach (byte b in bu)
    {
        bw.BaseStream.WriteByte(b);
    }
    bw.Close();
    st.Close();                    

    // That's it.
}

Functions used:

    private static byte[] stringToBytes(String str)
    {
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        Byte[] bytes = encoding.GetBytes(str);
        return bytes;
    }

   private static byte[] hashPieces(string file, int pieceLength)
    {

        SHA1 sha1 = new SHA1CryptoServiceProvider();

        StreamReader inn = new StreamReader(file);
        MemoryStream pieces = new MemoryStream();
        byte[] bytes = new byte[pieceLength];
        byte[] digest = new byte[20];
        int pieceByteCount = 0, readCount = inn.BaseStream.Read(bytes, 0, pieceLength);
        while (readCount != 0)
        {
            pieceByteCount += readCount;
            digest = sha1.ComputeHash(bytes, 0, readCount);
            if (pieceByteCount == pieceLength)
            {
                pieceByteCount = 0;
                foreach (byte b in digest)
                {
                    pieces.WriteByte(b);
                }
            }
            readCount = inn.BaseStream.Read(bytes, 0, pieceLength - pieceByteCount);
        }
        inn.Close();


        if (pieceByteCount > 0)
            foreach (byte b in digest)
            {
                pieces.WriteByte(b);
            }
        return pieces.ToArray();
    }

Solution

  • It depends on how you're trying to create it. If you run a website, and want to generate torrent files from uploaded files, then you'll obviously need server-side code.

    Generating a torrent file involves: adding the files you want to the torrent, and adding tracker info. Some popular trackers are:

    1. http://open.tracker.thepiratebay.org/announce
    2. http://www.torrent-downloads.to:2710/announce

    To create the .torrent file, you'll have to read the about the format of the file. A piece of Java that generates .torrent files is given at https://stackoverflow.com/a/2033298/384155