mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-13 22:53:36 +00:00
e56303798c
Initial SickGear for Python 3.
119 lines
4.4 KiB
Python
119 lines
4.4 KiB
Python
# Copyright (c) 2013 Chris Lucas, <chris@chrisjlucas.com>
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
# a copy of this software and associated documentation files (the
|
|
# "Software"), to deal in the Software without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
from ..compat import parse_qs, urlopen, urlparse
|
|
import bencode
|
|
|
|
import hashlib
|
|
import os.path
|
|
import re
|
|
|
|
|
|
class TorrentParser(object):
|
|
def __init__(self, torrent):
|
|
"""Decode and parse given torrent
|
|
|
|
@param torrent: handles: urls, file paths, string of torrent data
|
|
@type torrent: str
|
|
|
|
@raise AssertionError: Can be raised for a couple reasons:
|
|
- If _get_raw_torrent() couldn't figure out
|
|
what X{torrent} is
|
|
- if X{torrent} isn't a valid bencoded torrent file
|
|
"""
|
|
self.torrent = torrent
|
|
self._raw_torrent = None # : testing yo
|
|
self._torrent_decoded = None # : what up
|
|
self.file_type = None
|
|
|
|
self._get_raw_torrent()
|
|
assert self._raw_torrent is not None, 'Couldn\'t get raw_torrent.'
|
|
if self._torrent_decoded is None:
|
|
self._decode_torrent()
|
|
assert isinstance(self._torrent_decoded, dict), 'Invalid torrent file.'
|
|
self._parse_torrent()
|
|
|
|
@property
|
|
def raw_torrent(self):
|
|
return self._raw_torrent
|
|
|
|
def _is_raw(self):
|
|
raw = False
|
|
if isinstance(self.torrent, (str, bytes)):
|
|
if isinstance(self._decode_torrent(self.torrent), dict):
|
|
raw = True
|
|
else:
|
|
# reset self._torrent_decoded (currently equals False)
|
|
self._torrent_decoded = None
|
|
|
|
return raw
|
|
|
|
def _get_raw_torrent(self):
|
|
"""Get raw torrent data by determining what self.torrent is"""
|
|
# already raw?
|
|
if self._is_raw():
|
|
self.file_type = 'raw'
|
|
self._raw_torrent = self.torrent
|
|
return
|
|
# local file?
|
|
if os.path.isfile(self.torrent):
|
|
self.file_type = 'file'
|
|
self._raw_torrent = open(self.torrent, 'rb').read()
|
|
# url?
|
|
elif re.search(r'^(http|ftp)s?://', self.torrent, re.I):
|
|
self.file_type = 'url'
|
|
self._raw_torrent = urlopen(self.torrent).read()
|
|
# magnet link?
|
|
elif re.match(r'magnet:', self.torrent, re.I):
|
|
self.file_type = 'url'
|
|
query = {}
|
|
try:
|
|
parsed = urlparse(self.torrent)
|
|
query = parse_qs(parsed.query)
|
|
except (BaseException, Exception):
|
|
pass
|
|
self.title = query.get('dn', [''])[0]
|
|
self.info_hash = query.get('xt', [''])[0].split(':')[-1]
|
|
self.trackers = query.get('tr', [])
|
|
self._torrent_decoded = query
|
|
self._raw_torrent = self.torrent
|
|
|
|
def _decode_torrent(self, raw_torrent=None):
|
|
if raw_torrent is None:
|
|
raw_torrent = self._raw_torrent
|
|
self._torrent_decoded = bencode.decode(raw_torrent)
|
|
return self._torrent_decoded
|
|
|
|
def _calc_info_hash(self):
|
|
self.info_hash = None
|
|
if 'info' in self._torrent_decoded:
|
|
info_encoded = bencode.encode(self._torrent_decoded['info'])
|
|
|
|
if info_encoded:
|
|
self.info_hash = hashlib.sha1(info_encoded).hexdigest().upper()
|
|
|
|
return self.info_hash
|
|
|
|
def _parse_torrent(self):
|
|
for k in self._torrent_decoded:
|
|
key = k.replace(' ', '_').lower()
|
|
setattr(self, key, self._torrent_decoded[k])
|
|
|
|
self._calc_info_hash()
|