This repository has been archived on 2024-05-09. You can view files and clone it, but cannot push or open issues/pull-requests.
ipodderx-core/BitTorrent/parsedir.py

151 lines
5.2 KiB
Python

# The contents of this file are subject to the BitTorrent Open Source License
# Version 1.1 (the License). You may not copy or use this file, in either
# source code or executable form, except in compliance with the License. You
# may obtain a copy of the License at http://www.bittorrent.com/license/.
#
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
# Written by John Hoffman and Uoti Urpala
import os
from sha import sha
from BitTorrent.bencode import bencode, bdecode
from BitTorrent.btformats import check_message
NOISY = False
def parsedir(directory, parsed, files, blocked, errfunc,
include_metainfo=True):
if NOISY:
errfunc('checking dir')
dirs_to_check = [directory]
new_files = {}
new_blocked = {}
while dirs_to_check: # first, recurse directories and gather torrents
directory = dirs_to_check.pop()
newtorrents = False
try:
dir_contents = os.listdir(directory)
except (IOError, OSError), e:
errfunc(_("Could not read directory ") + directory)
continue
for f in dir_contents:
if f.endswith('.torrent'):
newtorrents = True
p = os.path.join(directory, f)
try:
new_files[p] = [(os.path.getmtime(p),os.path.getsize(p)),0]
except (IOError, OSError), e:
errfunc(_("Could not stat ") + p + " : " + str(e))
if not newtorrents:
for f in dir_contents:
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 oldval is None: # new file
to_add.append(p)
continue
h = oldval[1]
if oldval[0] == v[0]: # file is unchanged from last parse
if h:
if p in blocked: # 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] = None # same broken unparseable file
continue
if p not in blocked and h in parsed: # modified; remove+add
if NOISY:
errfunc(_("removing %s (will re-add)") % p)
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 = new_file[0]
if new_file[1] in new_parsed: # duplicate
if p not in blocked or files[p][0] != v:
errfunc(_("**warning** %s is a duplicate torrent for %s") %
(p, new_parsed[new_file[1]]['path']))
new_blocked[p] = None
continue
if NOISY:
errfunc('adding '+p)
try:
ff = open(p, 'rb')
d = bdecode(ff.read())
check_message(d)
h = sha(bencode(d['info'])).digest()
new_file[1] = h
if new_parsed.has_key(h):
errfunc(_("**warning** %s is a duplicate torrent for %s") %
(p, new_parsed[h]['path']))
new_blocked[p] = None
continue
a = {}
a['path'] = p
f = os.path.basename(p)
a['file'] = f
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 include_metainfo:
a['metainfo'] = d
except:
errfunc(_("**warning** %s has errors") % p)
new_blocked[p] = None
continue
try:
ff.close()
except:
pass
if NOISY:
errfunc(_("... successful"))
new_parsed[h] = a
added[h] = a
for p,v in files.iteritems(): # and finally, mark removed torrents
if p not in new_files and p not in blocked:
if NOISY:
errfunc(_("removing %s") % p)
removed[v[1]] = parsed[v[1]]
if NOISY:
errfunc(_("done checking"))
return (new_parsed, new_files, new_blocked, added, removed)