Я поискал ответ на этот вопрос, но, кажется, могу найти только программное обеспечение, которое сделает это за вас. Кто-нибудь знает, как это сделать на Python?
Извлечь хеш SHA1 из торрент-файла
Ответы (3)
Я написал фрагмент кода на Python, который проверяет хэши загруженных файлов на соответствие содержимому .torrent-файла. Предполагая, что вы хотите проверить загрузку на наличие повреждений, это может оказаться полезным.
Чтобы использовать это, вам понадобится пакет bencode. Bencode - это формат сериализации, используемый в файлах .torrent. Он может упорядочивать списки, словари, строки и числа наподобие JSON.
Код берет хэши, содержащиеся в строке info['pieces']
:
torrent_file = open(sys.argv[1], "rb")
metainfo = bencode.bdecode(torrent_file.read())
info = metainfo['info']
pieces = StringIO.StringIO(info['pieces'])
Эта строка содержит последовательность из 20 байтовых хэшей (по одному на каждую часть). Затем эти хэши сравниваются с хешами частей файла (ов) на диске.
Единственная сложная часть этого кода - обработка многофайловых торрентов, потому что один торрент кусок может охватывать более одного файла (внутри BitTorrent обрабатывает многофайловые загрузки как один непрерывный файл) em>. Я использую функцию генератора pieces_generator()
, чтобы абстрагироваться от этого.
Вы можете прочитать спецификацию BitTorrent, чтобы понять это более подробно.
Полный код ниже:
import sys, os, hashlib, StringIO, bencode
def pieces_generator(info):
"""Yield pieces from download file(s)."""
piece_length = info['piece length']
if 'files' in info: # yield pieces from a multi-file torrent
piece = ""
for file_info in info['files']:
path = os.sep.join([info['name']] + file_info['path'])
print path
sfile = open(path.decode('UTF-8'), "rb")
while True:
piece += sfile.read(piece_length-len(piece))
if len(piece) != piece_length:
sfile.close()
break
yield piece
piece = ""
if piece != "":
yield piece
else: # yield pieces from a single file torrent
path = info['name']
print path
sfile = open(path.decode('UTF-8'), "rb")
while True:
piece = sfile.read(piece_length)
if not piece:
sfile.close()
return
yield piece
def corruption_failure():
"""Display error message and exit"""
print("download corrupted")
exit(1)
def main():
# Open torrent file
torrent_file = open(sys.argv[1], "rb")
metainfo = bencode.bdecode(torrent_file.read())
info = metainfo['info']
pieces = StringIO.StringIO(info['pieces'])
# Iterate through pieces
for piece in pieces_generator(info):
# Compare piece hash with expected hash
piece_hash = hashlib.sha1(piece).digest()
if (piece_hash != pieces.read(20)):
corruption_failure()
# ensure we've read all pieces
if pieces.read():
corruption_failure()
if __name__ == "__main__":
main()
Вот как я извлек значение HASH из торрент-файла:
#!/usr/bin/python
import sys, os, hashlib, StringIO
import bencode
def main():
# Open torrent file
torrent_file = open(sys.argv[1], "rb")
metainfo = bencode.bdecode(torrent_file.read())
info = metainfo['info']
print hashlib.sha1(bencode.bencode(info)).hexdigest()
if __name__ == "__main__":
main()
Это то же самое, что и запущенная команда:
transmissioncli -i test.torrent 2>/dev/null | grep "^hash:" | awk '{print $2}'
Надеюсь, поможет :)
bzrlib.bencode
из python-bzrlib .
- person marcz; 02.03.2017
Согласно this, вы сможете найти md5-суммы файлов, выполнив поиск по части данные, которые выглядят так:
d[...]6:md5sum32:[hash is here][...]e
(SHA не является частью спецификации)
md5sum: (optional) a 32-character hex[...] This is not used by BitTorrent at all, but it is included by some programs
- person Alex Jasmin; 04.04.2010
d[...]9:info_hash[length]:[SHA hash]e
- person Brendan Long; 04.04.2010