1
0

parsedir.py 4.7 KB

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