Created
March 28, 2018 19:24
-
-
Save johncf/f1606e33562b51f67aa53ffdddf2183c to your computer and use it in GitHub Desktop.
Torrent: download specific pieces with libtorrent
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python3 | |
import libtorrent as lt | |
with open("/path/to/file.torrent", "rb") as f: | |
e = lt.bdecode(f.read()) | |
info = lt.torrent_info(e) | |
print(info.num_pieces(), 'pieces') | |
files = info.files() | |
def humanize(size_bytes): | |
KB = 1 << 10 | |
MB = 1 << 20 | |
GB = 1 << 30 | |
if size_bytes < KB: | |
return '{} B'.format(size_bytes) | |
elif size_bytes < MB: | |
return '{:.1f} KiB'.format(size_bytes/KB) | |
elif size_bytes < GB: | |
return '{:.1f} MiB'.format(size_bytes/MB) | |
else: | |
return '{:.1f} GiB'.format(size_bytes/GB) | |
for i, f in enumerate(info.files()): | |
print(i, ':', f.path) | |
print(' size: {}, first piece: {}'.format(humanize(f.size), info.map_file(i, 0, 1).piece)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python3 | |
# TIP: Instead of executing this script from shell, do the following from an | |
# interactive python session (python shell): | |
# >>> exec(open("./torrent-dl.py").read()) | |
# after which do `h.resume()` to resume. Use `graceful_exit()` to quit properly. | |
# Modify the list `pp` as needed and do `h.prioritize_pieces(pp)`. | |
# TIP: Use https://stackoverflow.com/a/26102379/2849934 to generate a torrent file | |
# from a magnet link. | |
import libtorrent as lt | |
import os.path | |
import signal | |
import sys | |
import time | |
import __main__ | |
torr_path = '/path/to/file.torrent' | |
save_path = os.path.dirname(torr_path) | |
resume_path = os.path.splitext(torr_path)[0] + '.fastresume' | |
ses = lt.session() | |
ses.listen_on(7881, 7891) | |
with open(torr_path, "rb") as f: | |
e = lt.bdecode(f.read()) | |
info = lt.torrent_info(e) | |
params = { 'save_path': save_path, | |
'storage_mode': lt.storage_mode_t.storage_mode_sparse, | |
'ti': info, | |
'flags': lt.add_torrent_params_flags_t.flag_paused, | |
} | |
try: | |
with open(resume_path, 'rb') as f: | |
params['resume_data'] = f.read() | |
except: | |
pass | |
h = ses.add_torrent(params) | |
pp = [0]*info.num_pieces() | |
beg, end = 0, info.num_pieces() | |
# first and last pieces | |
p1 = (end - beg)//100 | |
pp[:p1] = [7]*p1 | |
pp[-p1:] = [7]*p1 | |
sz = (end - beg)//20 | |
# more pieces | |
mid = beg + (end - beg)//2 | |
pp[mid:mid+sz] = [6]*sz | |
h.prioritize_pieces(pp) | |
tqt = beg + 3*(end - beg)//4 | |
pp[tqt:tqt+2*sz] = [5]*(2*sz) | |
pp[tqt-2*sz:tqt] = [5]*(2*sz) | |
h.prioritize_pieces(pp) | |
def check_alerts(): | |
alerts = ses.pop_alerts() | |
for a in alerts: | |
print('alert:', a) | |
def graceful_exit(): | |
ses.pause() | |
check_alerts() | |
print("saving resume data...") | |
if h.is_valid(): | |
h.save_resume_data() | |
while True: | |
ses.wait_for_alert(3000) | |
a = ses.pop_alert() | |
if a is None: | |
print('alert wait timed out') | |
break | |
print('alert:', a) | |
if type(a) == lt.save_resume_data_alert: | |
data = lt.bencode(a.resume_data) | |
with open(resume_path, 'wb') as f: | |
f.write(data) | |
break | |
elif type(a) == lt.save_resume_data_failed_alert: | |
print('failed to save resume data') | |
break | |
sys.exit(0) | |
def print_status(): | |
check_alerts() | |
s = h.status() | |
print('{:.1f}% complete (down: {:.1f} kB/s up: {:.1f} kB/s peers: {}) {}'.format( | |
s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, | |
s.num_peers, s.state)) | |
if hasattr(__main__, '__file__'): # if not in an interactive session | |
def signal_handler(_sig, _frm): | |
graceful_exit() | |
signal.signal(signal.SIGINT, signal_handler) | |
h.resume() | |
while True: | |
print_status() | |
time.sleep(1) |
Do you know how I should config the
pp
to download a specific file with known size and first piece ?
pp
(piece-priority) is the list of priorities for every piece in the torrent. If you know which pieces a file belongs in, simply set high priority for those pieces. That is, you need to know the first piece and the number of pieces in the file, which can be calculated with file size divided by the size of a piece.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Do you know how I should config the
pp
to download a specific file with known size and first piece ?Or is there any way to do that? I think you might know that.
size: 2.8 GiB, first piece: 27340