GetTorrent.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. # The contents of this file are subject to the BitTorrent Open Source License
  2. # Version 1.1 (the License). You may not copy or use this file, in either
  3. # source code or executable form, except in compliance with the License. You
  4. # may obtain a copy of the License at http://www.bittorrent.com/license/.
  5. #
  6. # Software distributed under the License is distributed on an AS IS basis,
  7. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. # for the specific language governing rights and limitations under the
  9. # License.
  10. # GetTorrent -- abstraction which can get a .torrent file from multiple
  11. # sources: local file, url, etc.
  12. # written by Matt Chisholm and David Harrison
  13. import os
  14. import re
  15. from BitTorrent import zurllib
  16. from BTL.translation import _
  17. from BTL.bencode import bdecode, bencode
  18. from BTL.ConvertedMetainfo import ConvertedMetainfo
  19. from BTL.platform import get_cache_dir
  20. urlpat = re.compile('^\w+://')
  21. urlpat_torrent = re.compile('^torrent://')
  22. urlpat_bittorrent = re.compile('^bittorrent://')
  23. class GetTorrentException(Exception):
  24. pass
  25. class UnknownArgument(GetTorrentException):
  26. pass
  27. class URLException(GetTorrentException):
  28. pass
  29. class FileException(GetTorrentException):
  30. pass
  31. class MetainfoException(GetTorrentException):
  32. pass
  33. def get_quietly(arg):
  34. """Wrapper for GetTorrent.get() which works around an IE bug. If
  35. there's an error opening a file from the IE cache, act like we
  36. simply didn't get a file (because we didn't). This happens when
  37. IE passes us a path to a file in its cache that has already been
  38. deleted because it came from a website which set Pragma:No-Cache
  39. on it.
  40. """
  41. try:
  42. data = get(arg)
  43. except FileException, e:
  44. cache = get_cache_dir()
  45. if (cache is not None) and (cache in unicode(e.args[0])):
  46. data = None
  47. else:
  48. raise
  49. return data
  50. def _get(arg):
  51. """Obtains the contents of the .torrent metainfo file either from
  52. the local filesystem or from a remote server. 'arg' is either
  53. a filename or an URL.
  54. Returns data, the raw contents of the .torrent file. Any
  55. exception raised while obtaining the .torrent file or parsing
  56. its contents is caught and wrapped in one of the following
  57. errors: GetTorrent.URLException, GetTorrent.FileException,
  58. GetTorrent.MetainfoException, or GetTorrent.UnknownArgument.
  59. (All have the base class GetTorrent.GetTorrentException)
  60. """
  61. data = None
  62. arg_stripped = arg.strip()
  63. if os.access(arg, os.F_OK):
  64. data = get_file(arg)
  65. elif urlpat.match(arg_stripped):
  66. data = get_url(arg_stripped)
  67. else:
  68. raise UnknownArgument(_('Could not read "%s", it is neither a file nor a URL.') % arg)
  69. return data
  70. def get(arg):
  71. """Obtains the contents of the .torrent metainfo file either from
  72. the local filesystem or from a remote server. 'arg' is either
  73. a filename or an URL.
  74. Returns a ConvertedMetainfo object which is the parsed metainfo
  75. from the contents of the .torrent file. Any exception raised
  76. while obtaining the .torrent file or parsing its contents is
  77. caught and wrapped in one of the following errors:
  78. GetTorrent.URLException, GetTorrent.FileException,
  79. GetTorrent.MetainfoException, or GetTorrent.UnknownArgument.
  80. (All have the base class GetTorrent.GetTorrentException)
  81. """
  82. data = _get(arg)
  83. metainfo = None
  84. try:
  85. b = bdecode(data)
  86. metainfo = ConvertedMetainfo(b)
  87. except Exception, e:
  88. raise MetainfoException(
  89. (_('"%s" is not a valid torrent file (%s).') % (arg, unicode(e)))
  90. )
  91. return metainfo
  92. def get_url(url):
  93. """Downloads the .torrent metainfo file specified by the passed
  94. URL and returns data, the raw contents of the metainfo file.
  95. Any exception raised while trying to obtain the metainfo file
  96. is caught and GetTorrent.URLException is raised instead.
  97. """
  98. data = None
  99. err_str = ((_('Could not download or open "%s"')% url) + '\n' +
  100. _("Try using a web browser to download the torrent file."))
  101. u = None
  102. # pending protocol changes, convert:
  103. # torrent://http://path.to/file
  104. # and:
  105. # bittorrent://http://path.to/file
  106. # to:
  107. # http://path.to/file
  108. url = urlpat_torrent.sub('', url)
  109. url = urlpat_bittorrent.sub('', url)
  110. try:
  111. u = zurllib.urlopen(url)
  112. data = u.read()
  113. u.close()
  114. except Exception, e:
  115. if u is not None:
  116. u.close()
  117. raise URLException(err_str + "\n(%s)" % e)
  118. else:
  119. if u is not None:
  120. u.close()
  121. return data
  122. def get_file(filename):
  123. """Reads the .torrent metainfo file specified by the passed
  124. filename and returns data, the raw contents of the metainfo file.
  125. Any exception raised while trying to obtain the metainfo file is
  126. caught and GetTorrent.FileException is raised instead.
  127. """
  128. data = None
  129. f = None
  130. try:
  131. f = file(filename, 'rb')
  132. data = f.read()
  133. f.close()
  134. except Exception, e:
  135. if f is not None:
  136. f.close()
  137. raise FileException((_("Could not read %s") % filename) + (': %s' % unicode(e.args[0])))
  138. return data