Blame | Last modification | View Log | Download
# Written by John Hoffman and Uoti Urpala
# see LICENSE.txt for license information
from bencode import bencode, bdecode
from BT1.btformats import check_info
from os.path import exists, isfile
from sha import sha
import sys, os
try:
True
except:
True = 1
False = 0
NOISY = False
def _errfunc(x):
print ":: "+x
def parsedir(directory, parsed, files, blocked,
exts = ['.torrent'], return_metainfo = False, errfunc = _errfunc):
if NOISY:
errfunc('checking dir')
dirs_to_check = [directory]
new_files = {}
new_blocked = {}
torrent_type = {}
while dirs_to_check: # first, recurse directories and gather torrents
directory = dirs_to_check.pop()
newtorrents = False
for f in os.listdir(directory):
newtorrent = None
for ext in exts:
if f.endswith(ext):
newtorrent = ext[1:]
break
if newtorrent:
newtorrents = True
p = os.path.join(directory, f)
new_files[p] = [(os.path.getmtime(p), os.path.getsize(p)), 0]
torrent_type[p] = newtorrent
if not newtorrents:
for f in os.listdir(directory):
p = os.path.join(directory, f)
if os.path.isdir(p):
dirs_to_check.append(p)
new_parsed = {}
to_add = []
added = {}
removed = {}
# files[path] = [(modification_time, size), hash], hash is 0 if the file
# has not been successfully parsed
for p,v in new_files.items(): # re-add old items and check for changes
oldval = files.get(p)
if not oldval: # new file
to_add.append(p)
continue
h = oldval[1]
if oldval[0] == v[0]: # file is unchanged from last parse
if h:
if blocked.has_key(p): # parseable + blocked means duplicate
to_add.append(p) # other duplicate may have gone away
else:
new_parsed[h] = parsed[h]
new_files[p] = oldval
else:
new_blocked[p] = 1 # same broken unparseable file
continue
if parsed.has_key(h) and not blocked.has_key(p):
if NOISY:
errfunc('removing '+p+' (will re-add)')
removed[h] = parsed[h]
to_add.append(p)
to_add.sort()
for p in to_add: # then, parse new and changed torrents
new_file = new_files[p]
v,h = new_file
if new_parsed.has_key(h): # duplicate
if not blocked.has_key(p) or files[p][0] != v:
errfunc('**warning** '+
p +' is a duplicate torrent for '+new_parsed[h]['path'])
new_blocked[p] = 1
continue
if NOISY:
errfunc('adding '+p)
try:
ff = open(p, 'rb')
d = bdecode(ff.read())
check_info(d['info'])
h = sha(bencode(d['info'])).digest()
new_file[1] = h
if new_parsed.has_key(h):
errfunc('**warning** '+
p +' is a duplicate torrent for '+new_parsed[h]['path'])
new_blocked[p] = 1
continue
a = {}
a['path'] = p
f = os.path.basename(p)
a['file'] = f
a['type'] = torrent_type[p]
i = d['info']
l = 0
nf = 0
if i.has_key('length'):
l = i.get('length',0)
nf = 1
elif i.has_key('files'):
for li in i['files']:
nf += 1
if li.has_key('length'):
l += li['length']
a['numfiles'] = nf
a['length'] = l
a['name'] = i.get('name', f)
def setkey(k, d = d, a = a):
if d.has_key(k):
a[k] = d[k]
setkey('failure reason')
setkey('warning message')
setkey('announce-list')
if return_metainfo:
a['metainfo'] = d
except:
errfunc('**warning** '+p+' has errors')
new_blocked[p] = 1
continue
try:
ff.close()
except:
pass
if NOISY:
errfunc('... successful')
new_parsed[h] = a
added[h] = a
for p,v in files.items(): # and finally, mark removed torrents
if not new_files.has_key(p) and not blocked.has_key(p):
if NOISY:
errfunc('removing '+p)
removed[v[1]] = parsed[v[1]]
if NOISY:
errfunc('done checking')
return (new_parsed, new_files, new_blocked, added, removed)