Subversion Repositories svnkaklik

Rev

Details | Last modification | View Log

Rev Author Line No. Line
36 kaklik 1
# Written by John Hoffman and Uoti Urpala
2
# see LICENSE.txt for license information
3
from bencode import bencode, bdecode
4
from BT1.btformats import check_info
5
from os.path import exists, isfile
6
from sha import sha
7
import sys, os
8
 
9
try:
10
    True
11
except:
12
    True = 1
13
    False = 0
14
 
15
NOISY = False
16
 
17
def _errfunc(x):
18
    print ":: "+x
19
 
20
def parsedir(directory, parsed, files, blocked,
21
             exts = ['.torrent'], return_metainfo = False, errfunc = _errfunc):
22
    if NOISY:
23
        errfunc('checking dir')
24
    dirs_to_check = [directory]
25
    new_files = {}
26
    new_blocked = {}
27
    torrent_type = {}
28
    while dirs_to_check:    # first, recurse directories and gather torrents
29
        directory = dirs_to_check.pop()
30
        newtorrents = False
31
        for f in os.listdir(directory):
32
            newtorrent = None
33
            for ext in exts:
34
                if f.endswith(ext):
35
                    newtorrent = ext[1:]
36
                    break
37
            if newtorrent:
38
                newtorrents = True
39
                p = os.path.join(directory, f)
40
                new_files[p] = [(os.path.getmtime(p), os.path.getsize(p)), 0]
41
                torrent_type[p] = newtorrent
42
        if not newtorrents:
43
            for f in os.listdir(directory):
44
                p = os.path.join(directory, f)
45
                if os.path.isdir(p):
46
                    dirs_to_check.append(p)
47
 
48
    new_parsed = {}
49
    to_add = []
50
    added = {}
51
    removed = {}
52
    # files[path] = [(modification_time, size), hash], hash is 0 if the file
53
    # has not been successfully parsed
54
    for p,v in new_files.items():   # re-add old items and check for changes
55
        oldval = files.get(p)
56
        if not oldval:          # new file
57
            to_add.append(p)
58
            continue
59
        h = oldval[1]
60
        if oldval[0] == v[0]:   # file is unchanged from last parse
61
            if h:
62
                if blocked.has_key(p):  # parseable + blocked means duplicate
63
                    to_add.append(p)    # other duplicate may have gone away
64
                else:
65
                    new_parsed[h] = parsed[h]
66
                new_files[p] = oldval
67
            else:
68
                new_blocked[p] = 1  # same broken unparseable file
69
            continue
70
        if parsed.has_key(h) and not blocked.has_key(p):
71
            if NOISY:
72
                errfunc('removing '+p+' (will re-add)')
73
            removed[h] = parsed[h]
74
        to_add.append(p)
75
 
76
    to_add.sort()
77
    for p in to_add:                # then, parse new and changed torrents
78
        new_file = new_files[p]
79
        v,h = new_file
80
        if new_parsed.has_key(h): # duplicate
81
            if not blocked.has_key(p) or files[p][0] != v:
82
                errfunc('**warning** '+
83
                    p +' is a duplicate torrent for '+new_parsed[h]['path'])
84
            new_blocked[p] = 1
85
            continue
86
 
87
        if NOISY:
88
            errfunc('adding '+p)
89
        try:
90
            ff = open(p, 'rb')
91
            d = bdecode(ff.read())
92
            check_info(d['info'])
93
            h = sha(bencode(d['info'])).digest()
94
            new_file[1] = h
95
            if new_parsed.has_key(h):
96
                errfunc('**warning** '+
97
                    p +' is a duplicate torrent for '+new_parsed[h]['path'])
98
                new_blocked[p] = 1
99
                continue
100
 
101
            a = {}
102
            a['path'] = p
103
            f = os.path.basename(p)
104
            a['file'] = f
105
            a['type'] = torrent_type[p]
106
            i = d['info']
107
            l = 0
108
            nf = 0
109
            if i.has_key('length'):
110
                l = i.get('length',0)
111
                nf = 1
112
            elif i.has_key('files'):
113
                for li in i['files']:
114
                    nf += 1
115
                    if li.has_key('length'):
116
                        l += li['length']
117
            a['numfiles'] = nf
118
            a['length'] = l
119
            a['name'] = i.get('name', f)
120
            def setkey(k, d = d, a = a):
121
                if d.has_key(k):
122
                    a[k] = d[k]
123
            setkey('failure reason')
124
            setkey('warning message')
125
            setkey('announce-list')
126
            if return_metainfo:
127
                a['metainfo'] = d
128
        except:
129
            errfunc('**warning** '+p+' has errors')
130
            new_blocked[p] = 1
131
            continue
132
        try:
133
            ff.close()
134
        except:
135
            pass
136
        if NOISY:
137
            errfunc('... successful')
138
        new_parsed[h] = a
139
        added[h] = a
140
 
141
    for p,v in files.items():       # and finally, mark removed torrents
142
        if not new_files.has_key(p) and not blocked.has_key(p):
143
            if NOISY:
144
                errfunc('removing '+p)
145
            removed[v[1]] = parsed[v[1]]
146
 
147
    if NOISY:
148
        errfunc('done checking')
149
    return (new_parsed, new_files, new_blocked, added, removed)
150