mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-12 22:23:38 +00:00
160 lines
5.5 KiB
Python
160 lines
5.5 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 rtorrent.compat import is_py3
|
|
import os.path
|
|
import re
|
|
import rtorrent.lib.bencode as bencode
|
|
import hashlib
|
|
|
|
if is_py3():
|
|
from urllib.request import urlopen # @UnresolvedImport @UnusedImport
|
|
else:
|
|
from urllib2 import urlopen # @UnresolvedImport @Reimport
|
|
|
|
|
|
class TorrentParser():
|
|
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()
|
|
|
|
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("^(http|ftp)s?:\/\/", self.torrent, re.I):
|
|
self.file_type = "url"
|
|
self._raw_torrent = urlopen(self.torrent).read()
|
|
|
|
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.keys():
|
|
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()
|
|
|
|
|
|
class NewTorrentParser(object):
|
|
@staticmethod
|
|
def _read_file(fp):
|
|
return fp.read()
|
|
|
|
@staticmethod
|
|
def _write_file(fp):
|
|
fp.write()
|
|
return fp
|
|
|
|
@staticmethod
|
|
def _decode_torrent(data):
|
|
return bencode.decode(data)
|
|
|
|
def __init__(self, input):
|
|
self.input = input
|
|
self._raw_torrent = None
|
|
self._decoded_torrent = None
|
|
self._hash_outdated = False
|
|
|
|
if isinstance(self.input, (str, bytes)):
|
|
# path to file?
|
|
if os.path.isfile(self.input):
|
|
self._raw_torrent = self._read_file(open(self.input, "rb"))
|
|
else:
|
|
# assume input was the raw torrent data (do we really want
|
|
# this?)
|
|
self._raw_torrent = self.input
|
|
|
|
# file-like object?
|
|
elif self.input.hasattr("read"):
|
|
self._raw_torrent = self._read_file(self.input)
|
|
|
|
assert self._raw_torrent is not None, "Invalid input: input must be a path or a file-like object"
|
|
|
|
self._decoded_torrent = self._decode_torrent(self._raw_torrent)
|
|
|
|
assert isinstance(
|
|
self._decoded_torrent, dict), "File could not be decoded"
|
|
|
|
def _calc_info_hash(self):
|
|
self.info_hash = None
|
|
info_dict = self._torrent_decoded["info"]
|
|
self.info_hash = hashlib.sha1(bencode.encode(
|
|
info_dict)).hexdigest().upper()
|
|
|
|
return(self.info_hash)
|
|
|
|
def set_tracker(self, tracker):
|
|
self._decoded_torrent["announce"] = tracker
|
|
|
|
def get_tracker(self):
|
|
return self._decoded_torrent.get("announce")
|