Чтение набора файлов из торрента - PullRequest
12 голосов
/ 02 января 2009

Я хочу (быстро) собрать программу / скрипт для чтения набора файлов из .torrent-файла. Затем я хочу использовать этот набор для удаления любых файлов из определенного каталога, которые не принадлежат к торренту.

Есть какие-нибудь рекомендации по удобной библиотеке для чтения этого индекса из файла .torrent? Хотя я не возражаю против этого, я не хочу углубляться в спецификацию bittorrent и запускать загрузку кода с нуля для этой простой цели.

У меня нет предпочтений по языку.

Ответы [ 5 ]

19 голосов
/ 02 января 2009

Я бы использовал растербар libtorrent , который представляет собой небольшую и быструю библиотеку C ++.
Для перебора файлов вы можете использовать класс torrent_info (begin_files (), end_files ()).

Существует также интерфейс Python для libtorrent:

import libtorrent
info = libtorrent.torrent_info('test.torrent')
for f in info.files():
    print "%s - %s" % (f.path, f.size)
17 голосов
/ 14 февраля 2009

Effbot ответил на ваш вопрос . Вот полный код для чтения списка файлов из .torrent-файла (Python 2.4+):

import re

def tokenize(text, match=re.compile("([idel])|(\d+):|(-?\d+)").match):
    i = 0
    while i < len(text):
        m = match(text, i)
        s = m.group(m.lastindex)
        i = m.end()
        if m.lastindex == 2:
            yield "s"
            yield text[i:i+int(s)]
            i = i + int(s)
        else:
            yield s

def decode_item(next, token):
    if token == "i":
        # integer: "i" value "e"
        data = int(next())
        if next() != "e":
            raise ValueError
    elif token == "s":
        # string: "s" value (virtual tokens)
        data = next()
    elif token == "l" or token == "d":
        # container: "l" (or "d") values "e"
        data = []
        tok = next()
        while tok != "e":
            data.append(decode_item(next, tok))
            tok = next()
        if token == "d":
            data = dict(zip(data[0::2], data[1::2]))
    else:
        raise ValueError
    return data

def decode(text):
    try:
        src = tokenize(text)
        data = decode_item(src.next, src.next())
        for token in src: # look for more tokens
            raise SyntaxError("trailing junk")
    except (AttributeError, ValueError, StopIteration):
        raise SyntaxError("syntax error")
    return data

if __name__ == "__main__":
    data = open("test.torrent", "rb").read()
    torrent = decode(data)
    for file in torrent["info"]["files"]:
        print "%r - %d bytes" % ("/".join(file["path"]), file["length"])
2 голосов
/ 02 января 2009

bencode.py из оригинального клиента Mainline BitTorrent 5.x (http://download.bittorrent.com/dl/BitTorrent-5.2.2.tar.gz) даст вам в значительной степени справочную реализацию в Python.

Он имеет зависимость импорта от пакета BTL, но его тривиально легко удалить. Затем вы посмотрите на bencode.bdecode (filecontent) ['info'] ['files'].

1 голос
/ 03 июня 2012

Развивая идеи выше, я сделал следующее:

~> cd ~/bin

~/bin> ls torrent*
torrent-parse.py  torrent-parse.sh

~/bin> cat torrent-parse.py
# torrent-parse.py
import sys
import libtorrent

# get the input torrent file
if (len(sys.argv) > 1):
    torrent = sys.argv[1]
else:
    print "Missing param: torrent filename"
    sys.exit()
# get names of files in the torrent file
info = libtorrent.torrent_info(torrent);
for f in info.files():
    print "%s - %s" % (f.path, f.size)

~/bin> cat torrent-parse.sh
#!/bin/bash
if [ $# -lt 1 ]; then
  echo "Missing param: torrent filename"
  exit 0
fi

python torrent-parse.py "$*"

Вы хотите установить соответствующие разрешения, чтобы сделать исполняемый скрипт оболочки:

~/bin> chmod a+x torrent-parse.sh

Надеюсь, это кому-нибудь поможет:)

0 голосов
/ 04 марта 2017

Вот код из ответа Константина выше, немного модифицированный для обработки символов Юникода в именах файлов торрента и имен файлов набора в информации о торренте:

import re

def tokenize(text, match=re.compile("([idel])|(\d+):|(-?\d+)").match):
    i = 0
    while i < len(text):
        m = match(text, i)
        s = m.group(m.lastindex)
        i = m.end()
        if m.lastindex == 2:
            yield "s"
            yield text[i:i+int(s)]
            i = i + int(s)
        else:
            yield s

def decode_item(next, token):
    if token == "i":
        # integer: "i" value "e"
        data = int(next())
        if next() != "e":
            raise ValueError
    elif token == "s":
        # string: "s" value (virtual tokens)
        data = next()
    elif token == "l" or token == "d":
        # container: "l" (or "d") values "e"
        data = []
        tok = next()
        while tok != "e":
            data.append(decode_item(next, tok))
            tok = next()
        if token == "d":
            data = dict(zip(data[0::2], data[1::2]))
    else:
        raise ValueError
    return data

def decode(text):
    try:
        src = tokenize(text)
        data = decode_item(src.next, src.next())
        for token in src: # look for more tokens
            raise SyntaxError("trailing junk")
    except (AttributeError, ValueError, StopIteration):
        raise SyntaxError("syntax error")
    return data

n = 0
if __name__ == "__main__":
    data = open("C:\\Torrents\\test.torrent", "rb").read()
    torrent = decode(data)
    for file in torrent["info"]["files"]:
        n = n + 1
        filenamepath = file["path"]     
        print str(n) + " -- " + ', '.join(map(str, filenamepath))
        fname = ', '.join(map(str, filenamepath))

        print fname + " -- " + str(file["length"])
...