flexget.plugins.plugin_nzbmatrix
Covered: 52 lines
Missed: 71 lines
Skipped 20 lines
Percent: 42 %
  1
import logging
  2
from flexget.entry import Entry
  3
from flexget.plugin import internet, register_plugin
  4
from flexget.utils.tools import urlopener
  6
timeout = 10
  7
import socket
  8
socket.setdefaulttimeout(timeout)
 10
log = logging.getLogger('nzbmatrix')
 13
class NzbMatrix(object):
 14
    """NZBMatrix search plugin."""
 16
    def validator(self):
 17
        from flexget import validator
 18
        nzbmatrix = validator.factory('dict')
 19
        nzbmatrix.accept('integer', key='catid')
 20
        nzbmatrix.accept('integer', key='num')
 21
        nzbmatrix.accept('integer', key='age')
 22
        nzbmatrix.accept('choice', key='region').accept_choices(
 23
            ['1', '2', '3', 'PAL', 'NTSC', 'FREE'], ignore_case=True)
 24
        nzbmatrix.accept('text', key='group')
 25
        nzbmatrix.accept('text', key='username', required=True)
 26
        nzbmatrix.accept('text', key='apikey', required=True)
 27
        nzbmatrix.accept('integer', key='larger')
 28
        nzbmatrix.accept('integer', key='smaller')
 29
        nzbmatrix.accept('integer', key='minhits')
 30
        nzbmatrix.accept('integer', key='maxhits')
 31
        nzbmatrix.accept('integer', key='maxage')
 32
        nzbmatrix.accept('boolean', key='englishonly')
 35
        nzbmatrix.accept('choice', key='searchin').accept_choices(
 36
            ['name', 'subject', 'weblink'], ignore_case=True)
 37
        return nzbmatrix
 40
    def search(self, query, comparator, config=None):
 42
        import urllib
 43
        params = self.getparams(config)
 44
        params['search'] = self.clean(query)
 45
        search_url = 'https://api.nzbmatrix.com/v1.1/search.php?' + urllib.urlencode(params)
 46
        results = self.nzbid_from_search(search_url, params['search'], query)
 47
        if not results:
 48
            return []
 49
        else:
 50
            entries = []
 51
            for result in results:
 52
                entry = Entry()
 53
                entry['title'] = result['NZBNAME']
 54
                download_params = {"username": params['username'], 'apikey': params['apikey'], 'id': result['NZBID']}
 55
                entry['url'] = "http://api.nzbmatrix.com/v1.1/download.php?" + urllib.urlencode(download_params)
 56
                entries.append(entry)
 57
            return entries
 59
    def getparams(self, config):
 62
        params = config
 63
        if 'searchin' in params:
 64
            params['searchin'] = params['searchin'].lower()
 65
        if 'region' in params:
 66
            if params['region'].lower() == 'pal':
 67
                params['region'] = 1
 68
            if params['region'].lower() == 'ntsc':
 69
                params['region'] = 2
 70
            if params['region'].lower() == 'free':
 71
                params['region'] = 3
 72
        if 'englishonly' in params:
 73
            if params['englishonly']:
 74
                params['englishonly'] = 1
 75
            else:
 76
                del params['englishonly']
 77
        return params
 79
    def clean(self, s):
 80
        """clean the title name for search"""
 82
        return s.replace('.', ' ').replace('_', ' ').replace(',', '')\
 83
                         .replace('-', ' ').strip().lower()
 85
    @internet(log)
 86
    def nzbid_from_search(self, url, name, query):
 87
        """Parses nzb download url from api results"""
 88
        import time
 89
        import difflib
 90
        matched_results = []
 91
        log.debug("Sleeping to respect nzbmatrix rules about hammering the API")
 92
        time.sleep(10)
 93
        apireturn = self.parse_nzb_matrix_api(urlopener(url, log).read(),
 94
                                              query)
 95
        if not apireturn:
 96
            return None
 97
        else:
 98
            names = []
 99
            for result in apireturn:
100
                names.append(result["NZBNAME"])
101
            matches = difflib.get_close_matches(name, names, 1, 0.3)
102
            if len(matches) == 0:
103
                return None
104
            else:
105
                for result in apireturn:
106
                    if result["NZBNAME"] == matches[0]:
107
                        break
108
            for match in matches: # Already sorted
109
                for result in apireturn:
110
                    if result.get(match, False):
111
                        matched_results.append(result)
112
            return matched_results
114
    def parse_nzb_matrix_api(self, apireturn, title):
115
        import re
116
        apireturn = str(apireturn)
117
        if (apireturn == "error:nothing_found" or
118
            apireturn == "error:no_nzb_found"):
119
            log.debug("Nothing found from nzbmatrix for search on %s" % title)
120
            return []
121
        elif apireturn[:6] == 'error:':
122
            log.error("Error recieved from nzbmatrix API: %s" % apireturn[6:])
123
            return []
124
        results = []
125
        api_result = {}
126
        apire = re.compile(r"([A-Z_]+):(.+);$")
127
        for line in apireturn.splitlines():
128
            match = apire.match(line)
129
            if not match and line == "|" and api_result != {}:
131
                results.append(api_result)
132
                api_result = dict()
133
            elif match:
134
                api_result[match.group(1)] = match.group(2)
135
            else:
136
                log.debug("Recieved non-matching line in nzbmatrix API search: "
137
                          "%s" % line)
138
        if api_result != {}:
139
            results.append(api_result)
140
        return results
142
register_plugin(NzbMatrix, 'nzbmatrix', groups=['search'])