Skip to content

Instantly share code, notes, and snippets.

@edavis
Created November 23, 2023 06:48
Show Gist options
  • Save edavis/2296f999314bda09b79b1f5ca7e44ed6 to your computer and use it in GitHub Desktop.
Save edavis/2296f999314bda09b79b1f5ca7e44ed6 to your computer and use it in GitHub Desktop.
Parse a directory of torrent files and return the total size of all files within
#!/usr/bin/env python
import os, glob
from io import BytesIO
class End(Exception): pass
def decode(stream):
delim = stream.read(1)
if delim == b'd':
values = {}
while True:
try:
key = decode(stream)
val = decode(stream)
values.update({key: val})
except End:
break
return values
elif delim == b'l':
values = []
while True:
try:
val = decode(stream)
values.append(val)
except End:
break
return values
elif delim == b'i':
t = ''
while True:
d = stream.read(1)
if d == b'e':
break
t += d.decode()
return int(t, 10)
elif delim == b'e':
raise End
else: # byte string
t = delim.decode()
while True:
d = stream.read(1)
if d == b':':
break
t += d.decode()
return stream.read(int(t, 10))
def human_readable(size, suffix='B'):
fmt = '{:3.1f}{}{}'
units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']
for unit in units:
if abs(size) < 1024.0:
return fmt.format(size, unit, suffix)
size /= 1024.0
return fmt.format(size, 'Yi', suffix)
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('input')
args = parser.parse_args()
if os.path.isdir(args.input):
torrents = glob.glob(args.input + '/*.torrent')
else:
torrents = [args.input]
total_bytes = 0
for torrent in torrents:
with open(torrent, 'rb') as fp:
stream = BytesIO(fp.read())
parsed = decode(stream)
info = parsed.get(b'info', {})
if b'files' in info: # multi
for fname in info[b'files']:
# print(fname[b'path'], fname[b'length'])
total_bytes += fname[b'length']
elif b'length' in info: # single
# print(info[b'name'], info[b'length'])
total_bytes += info[b'length']
else:
print("could not find either 'files' or 'length' key in info dict")
print(human_readable(total_bytes))
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment