Beispiel #1
0
    def search(self, task, entry, config=None):
        """
        Search for name from piratebay.
        """
        if not isinstance(config, dict):
            config = {}
        self.set_urls(config.get('url', URL))
        sort = SORT.get(config.get('sort_by', 'seeds'))
        if config.get('sort_reverse'):
            sort += 1
        if isinstance(config.get('category'), int):
            category = config['category']
        else:
            category = CATEGORIES.get(config.get('category', 'all'))
        filter_url = '/0/%d/%d' % (sort, category)

        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string)

            # TPB search doesn't like dashes or quotes
            query = query.replace('-', ' ').replace("'", " ")

            # urllib.quote will crash if the unicode string has non ascii characters, so encode in utf-8 beforehand
            url = '%s/search/%s%s' % (self.url, quote(query.encode('utf-8')), filter_url)
            log.debug('Using %s as piratebay search url' % url)
            page = task.requests.get(url).content
            soup = get_soup(page)
            for link in soup.find_all('a', attrs={'class': 'detLink'}):
                entry = Entry()
                entry['title'] = self.extract_title(link)
                if not entry['title']:
                    log.error('Malformed search result. No title or url found. Skipping.')
                    continue
                href = link.get('href')
                if href.startswith('/'):  # relative link?
                    href = self.url + href
                entry['url'] = href
                tds = link.parent.parent.parent.find_all('td')
                entry['torrent_seeds'] = int(tds[-2].contents[0])
                entry['torrent_leeches'] = int(tds[-1].contents[0])
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                # Parse content_size
                size_text = link.find_next(attrs={'class': 'detDesc'}).get_text()
                if size_text:
                    size = re.search(r'Size (\d+(\.\d+)?\xa0(?:[PTGMK])?i?B)', size_text)
                    if size:
                        entry['content_size'] = parse_filesize(size.group(1))
                    else:
                        log.error(
                            'Malformed search result? Title: "%s", No size? %s',
                            entry['title'],
                            size_text,
                        )

                entries.add(entry)

        return sorted(entries, reverse=True, key=lambda x: x.get('torrent_availability'))
Beispiel #2
0
    def create_entries(self, soup, imdb_id=None):
        entries = []
        links = soup.findAll(
            'a', attrs={'href': re.compile(r'download\.php\?torrent=\d+')})
        rows = [l.find_parent('tr') for l in links]
        for row in rows:
            entry = Entry()
            entry['title'] = row.find('a',
                                      attrs={
                                          'href':
                                          re.compile(r'detail\.php\?id')
                                      }).text
            dl_href = row.find('a',
                               attrs={
                                   'href':
                                   re.compile(r'download\.php\?torrent=\d+')
                               }).get('href')
            entry['url'] = 'http://piratethenet.org' + dl_href
            entry['torrent_seeds'] = int(
                row.find(title='Number of Seeders').text)
            entry['torrent_leeches'] = int(
                row.find(title='Number of Leechers').text)
            entry['torrent_availability'] = torrent_availability(
                entry['torrent_seeds'], entry['torrent_leeches'])

            entry['content_size'] = parse_filesize(str(
                row.find(title='Torrent size').text),
                                                   si=False)

            if imdb_id:
                entry['imdb_id'] = imdb_id
            entries.append(entry)
        return entries
Beispiel #3
0
    def entries_from_search(self, name, url=None):
        """Parses torrent download url from search results"""
        name = normalize_unicode(name)
        if not url:
            url = 'http://www.newtorrents.info/search/%s' % quote(
                name.encode('utf-8'), safe=b':/~?=&%'
            )

        log.debug('search url: %s' % url)

        html = requests.get(url).text
        # fix </SCR'+'IPT> so that BS does not crash
        # TODO: should use beautifulsoup massage
        html = re.sub(r'(</SCR.*?)...(.*?IPT>)', r'\1\2', html)

        soup = get_soup(html)
        # saving torrents in dict
        torrents = []
        for link in soup.find_all('a', attrs={'href': re.compile('down.php')}):
            torrent_url = 'http://www.newtorrents.info%s' % link.get('href')
            release_name = link.parent.next.get('title')
            # quick dirty hack
            seed = link.find_next('td', attrs={'class': re.compile('s')}).renderContents()
            if seed == 'n/a':
                seed = 0
            else:
                try:
                    seed = int(seed)
                except ValueError:
                    log.warning(
                        'Error converting seed value (%s) from newtorrents to integer.' % seed
                    )
                    seed = 0

            # TODO: also parse content_size and peers from results
            torrents.append(
                Entry(
                    title=release_name,
                    url=torrent_url,
                    torrent_seeds=seed,
                    torrent_availability=torrent_availability(seed, 0),
                )
            )
        # sort with seed number Reverse order
        torrents.sort(reverse=True, key=lambda x: x.get('torrent_availability', 0))
        # choose the torrent
        if not torrents:
            dashindex = name.rfind('-')
            if dashindex != -1:
                return self.entries_from_search(name[:dashindex])
            else:
                return torrents
        else:
            if len(torrents) == 1:
                log.debug('found only one matching search result.')
            else:
                log.debug(
                    'search result contains multiple matches, sorted %s by most seeders' % torrents
                )
            return torrents
Beispiel #4
0
    def search(self, task, entry, config=None):
        """
        Search for name from piratebay.
        """
        if not isinstance(config, dict):
            config = {}
        self.set_urls(config.get('url', URL))
        sort = SORT.get(config.get('sort_by', 'seeds'))
        if config.get('sort_reverse'):
            sort += 1
        if isinstance(config.get('category'), int):
            category = config['category']
        else:
            category = CATEGORIES.get(config.get('category', 'all'))
        filter_url = '/0/%d/%d' % (sort, category)

        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string)

            # TPB search doesn't like dashes or quotes
            query = query.replace('-', ' ').replace("'", " ")

            # urllib.quote will crash if the unicode string has non ascii characters, so encode in utf-8 beforehand
            url = '%s/search/%s%s' % (self.url, quote(query.encode('utf-8')), filter_url)
            log.debug('Using %s as piratebay search url' % url)
            page = task.requests.get(url).content
            soup = get_soup(page)
            for link in soup.find_all('a', attrs={'class': 'detLink'}):
                entry = Entry()
                entry['title'] = self.extract_title(link)
                if not entry['title']:
                    log.error('Malformed search result. No title or url found. Skipping.')
                    continue
                href = link.get('href')
                if href.startswith('/'):  # relative link?
                    href = self.url + href
                entry['url'] = href
                tds = link.parent.parent.parent.find_all('td')
                entry['torrent_seeds'] = int(tds[-2].contents[0])
                entry['torrent_leeches'] = int(tds[-1].contents[0])
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                # Parse content_size
                size_text = link.find_next(attrs={'class': 'detDesc'}).get_text()
                if size_text:
                    size = re.search(r'Size (\d+(\.\d+)?\xa0(?:[PTGMK])?i?B)', size_text)
                    if size:
                        entry['content_size'] = parse_filesize(size.group(1))
                    else:
                        log.error(
                            'Malformed search result? Title: "%s", No size? %s',
                            entry['title'],
                            size_text,
                        )

                entries.add(entry)

        return sorted(entries, reverse=True, key=lambda x: x.get('search_sort'))
Beispiel #5
0
    def create_entries(self, soup, imdb_id=None):
        entries = []
        links = soup.findAll('a', attrs={'href': re.compile(r'download\.php\?torrent=\d+')})
        rows = [l.find_parent('tr') for l in links]
        for row in rows:
            entry = Entry()
            entry['title'] = row.find('a', attrs={'href': re.compile(r'detail\.php\?id')}).text
            dl_href = row.find('a', attrs={'href': re.compile(r'download\.php\?torrent=\d+')}).get(
                'href'
            )
            entry['url'] = 'http://piratethenet.org' + dl_href
            entry['torrent_seeds'] = int(row.find(title='Number of Seeders').text)
            entry['torrent_leeches'] = int(row.find(title='Number of Leechers').text)
            entry['torrent_availability'] = torrent_availability(
                entry['torrent_seeds'], entry['torrent_leeches']
            )

            entry['content_size'] = parse_filesize(
                str(row.find(title='Torrent size').text), si=False
            )

            if imdb_id:
                entry['imdb_id'] = imdb_id
            entries.append(entry)
        return entries
Beispiel #6
0
    def search(self, task, entry, config=None):
        config = self.process_config(config)
        feed = REPUTATIONS[config['reputation']]
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string.strip() + config.get('extra_terms', ''))
            for domain in ['is', 'pl']:
                # urllib.quote will crash if the unicode string has non ascii characters, so encode in utf-8 beforehand
                url = 'http://torrentz2.%s/%s?f=%s' % (domain, feed, quote(query.encode('utf-8')))
                logger.debug('requesting: {}', url)
                try:
                    r = task.requests.get(url)
                    break
                except requests.ConnectionError as err:
                    # The different domains all resolve to the same ip, so only try more if it was a dns error
                    logger.warning('torrentz.{} connection failed. Error: {}', domain, err)
                    continue
                except requests.RequestException as err:
                    raise plugin.PluginError('Error getting torrentz search results: %s' % err)

            else:
                raise plugin.PluginError('Error getting torrentz search results')

            if not r.content.strip():
                raise plugin.PluginError(
                    'No data from %s. Maybe torrentz is blocking the FlexGet User-Agent' % url
                )

            rss = feedparser.parse(r.content)

            if rss.get('bozo_exception'):
                raise plugin.PluginError('Got bozo_exception (bad rss feed)')

            for item in rss.entries:
                m = re.search(
                    r'Size: ([\d]+) Mb Seeds: ([,\d]+) Peers: ([,\d]+) Hash: ([a-f0-9]+)',
                    item.description,
                    re.IGNORECASE,
                )
                if not m:
                    logger.debug('regexp did not find seeds / peer data')
                    continue

                entry = Entry()
                entry['title'] = item.title
                entry['url'] = item.link
                entry['content_size'] = int(m.group(1))
                entry['torrent_seeds'] = int(m.group(2).replace(',', ''))
                entry['torrent_leeches'] = int(m.group(3).replace(',', ''))
                entry['torrent_info_hash'] = m.group(4).upper()
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                entries.add(entry)

        logger.debug('Search got {} results', len(entries))
        return entries
Beispiel #7
0
    def search(self, task, entry, config=None):
        config = self.process_config(config)
        feed = REPUTATIONS[config['reputation']]
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string + config.get('extra_terms', ''))
            for domain in ['eu', 'is']:
                # urllib.quote will crash if the unicode string has non ascii characters, so encode in utf-8 beforehand
                url = 'http://torrentz2.%s/%s?f=%s' % (domain, feed, quote(query.encode('utf-8')))
                log.debug('requesting: %s' % url)
                try:
                    r = task.requests.get(url)
                    break
                except requests.ConnectionError as err:
                    # The different domains all resolve to the same ip, so only try more if it was a dns error
                    log.warning('torrentz.%s connection failed. Error: %s' % (domain, err))
                    continue
                except requests.RequestException as err:
                    raise plugin.PluginError('Error getting torrentz search results: %s' % err)

            else:
                raise plugin.PluginError('Error getting torrentz search results')

            if not r.content.strip():
                raise plugin.PluginError(
                    'No data from %s. Maybe torrentz is blocking the FlexGet User-Agent' % url
                )

            rss = feedparser.parse(r.content)

            if rss.get('bozo_exception'):
                raise plugin.PluginError('Got bozo_exception (bad rss feed)')

            for item in rss.entries:
                m = re.search(
                    r'Size: ([\d]+) Mb Seeds: ([,\d]+) Peers: ([,\d]+) Hash: ([a-f0-9]+)',
                    item.description,
                    re.IGNORECASE,
                )
                if not m:
                    log.debug('regexp did not find seeds / peer data')
                    continue

                entry = Entry()
                entry['title'] = item.title
                entry['url'] = item.link
                entry['content_size'] = int(m.group(1))
                entry['torrent_seeds'] = int(m.group(2).replace(',', ''))
                entry['torrent_leeches'] = int(m.group(3).replace(',', ''))
                entry['torrent_info_hash'] = m.group(4).upper()
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                entries.add(entry)

        log.debug('Search got %d results' % len(entries))
        return entries
Beispiel #8
0
    def search(self, task, entry, config):
        """Search for entries on HeBits"""

        account_info = self._fetch_account_info(self.user_profile_url, config)
        params = {
            'action': 'browse',
            'group_results': 0,
        }
        cookies = {"userid": f"{config['userid']}", "session": f"{config['session']}"}

        if 'category' in config:
            cat = HeBitsCategory[config['category']].value
            params[f'filter_cat[{cat}]'] = 1

        entries = set()
        params['order_by'] = HeBitsSort[config['order_by']].value
        params['order_way'] = 'desc' if config['order_desc'] else 'asc'

        for search_string in entry.get(
            'search_strings', [entry['title'], entry.get('original_title'), entry.get('imdb_id')]
        ):
            params['searchstr'] = search_string
            logger.debug('Using search params: {}', params)
            try:
                page = requests.get(self.search_url, cookies=cookies, params=params)
                page.raise_for_status()
                search_results_response = page.json()
            except RequestException as e:
                logger.error('HeBits request failed: {}', e)
                continue
            if search_results_response['status'] != 'success':
                logger.error('HeBits request failed: server error')
                continue

            search_results = search_results_response['response']['results']
            for result in search_results:
                torrent_id = result['torrents'][0]['torrentId']
                seeders = result['torrents'][0]['seeders']
                leechers = result['torrents'][0]['leechers']
                size = result['torrents'][0]['size'] / 2**20
                title = result['torrents'][0]['release']

                entry = Entry(
                    torrent_seeds=seeders,
                    torrent_leeches=leechers,
                    torrent_availability=torrent_availability(seeders, leechers),
                    content_size=size,
                    title=title,
                    torrent_freeleech=result['torrents'][0]['isFreeleech'],
                    torrent_triple_up=result['torrents'][0]['isUploadX3'],
                    torrent_double_up=result['torrents'][0]['isUploadX2'],
                    url=f"{self.download_url}?action=download&id={torrent_id}&authkey={account_info['authkey']}&torrent_pass={account_info['passkey']}",
                )
                entries.add(entry)

        return entries
Beispiel #9
0
    def search(self, task, entry, config=None):
        entries = set()
        search_strings = [
            normalize_unicode(s)
            for s in entry.get('search_strings', [entry['title']])
        ]
        for search_string in search_strings:
            url = 'https://yts.am/api/v2/list_movies.json?query_term=%s' % (
                quote(search_string.encode('utf-8')))

            log.debug('requesting: %s' % url)

            try:
                result = requests.get(url)
                try:
                    data = result.json()
                except ValueError:
                    log.debug('Could not decode json from response: %s',
                              result.text)
                    raise plugin.PluginError('Error getting result from yts.')
            except requests.RequestException as e:
                raise plugin.PluginError(
                    'Could not retrieve query from yts (%s)' % e.args[0])
            if not data['status'] == 'ok':
                raise plugin.PluginError('failed to query YTS')

            try:
                if data['data']['movie_count'] > 0:
                    for item in data['data']['movies']:
                        for torrent in item['torrents']:
                            entry = Entry()
                            entry['title'] = item['title']
                            entry['year'] = item['year']
                            entry['url'] = torrent['url']
                            entry['content_size'] = parse_filesize(
                                str(torrent['size_bytes']) + "b")
                            entry['torrent_seeds'] = torrent['seeds']
                            entry['torrent_leeches'] = torrent['peers']
                            entry['torrent_info_hash'] = torrent['hash']
                            entry[
                                'torrent_availability'] = torrent_availability(
                                    entry['torrent_seeds'],
                                    entry['torrent_leeches'])
                            entry['quality'] = torrent['quality']
                            entry['imdb_id'] = item['imdb_code']
                            if entry.isvalid():
                                entries.add(entry)
            except Exception:
                log.debug('invalid return structure from YTS')

        log.debug('Search got %d results' % len(entries))
        return entries
Beispiel #10
0
 def json_to_entry(self, json_result: dict) -> Entry:
     entry = Entry()
     entry['title'] = json_result['name']
     entry['torrent_seeds'] = int(json_result['seeders'])
     entry['torrent_leeches'] = int(json_result['leechers'])
     entry['torrent_timestamp'] = int(json_result['added'])  # custom field for sorting by date
     entry['torrent_availability'] = torrent_availability(
         entry['torrent_seeds'], entry['torrent_leeches']
     )
     entry['content_size'] = int(round(int(json_result['size']) / (1024 * 1024)))
     entry['torrent_info_hash'] = json_result['info_hash']
     entry['url'] = self.info_hash_to_magnet(json_result['info_hash'], json_result['name'])
     return entry
Beispiel #11
0
    def extract_entry_from_soup(self, soup):
        table = soup.find('div', {'id': 'main_table'})
        if table is None:
            raise PluginError(
                'Could not fetch results table from Fuzer, aborting')

        log.trace('fuzer results table: %s', table)
        table = table.find('table', {'class': 'table_info'})
        if len(table.find_all('tr')) == 1:
            log.debug('No search results were returned from Fuzer, continuing')
            return []

        entries = []
        for tr in table.find_all("tr"):
            if not tr.get('class') or 'colhead_dark' in tr.get('class'):
                continue
            name = tr.find('div', {'class': 'main_title'}).find('a').text
            torrent_name = re.search(
                '\\n(.*)',
                tr.find('div', {
                    'style': 'float: right;'
                }).find('a')['title']).group(1)
            attachment_link = tr.find('div', {
                'style': 'float: right;'
            }).find('a')['href']
            attachment_id = re.search(r'attachmentid=(\d+)',
                                      attachment_link).group(1)
            raw_size = tr.find_all('td',
                                   {'class': 'inline_info'})[0].text.strip()
            seeders = int(tr.find_all('td', {'class': 'inline_info'})[2].text)
            leechers = int(tr.find_all('td', {'class': 'inline_info'})[3].text)

            e = Entry()
            e['title'] = name
            final_url = 'https://www.fuzer.me/rss/torrent.php/{}/{}/{}/{}'.format(
                attachment_id, self.user_id, self.rss_key, torrent_name)

            log.debug('RSS-ified download link: %s', final_url)
            e['url'] = final_url

            e['torrent_seeds'] = seeders
            e['torrent_leeches'] = leechers
            e['torrent_availibility'] = torrent_availability(
                e['torrent_seeds'], e['torrent_leeches'])

            size = re.search(r'(\d+(?:[.,]\d+)*)\s?([KMGTP]B)', raw_size)
            e['content_size'] = parse_filesize(size.group(0))

            entries.append(e)
        return entries
Beispiel #12
0
    def search(self, task, entry, config=None):
        entries = set()
        search_strings = [
            normalize_unicode(s) for s in entry.get('search_strings', [entry['title']])
        ]
        for search_string in search_strings:
            url = 'https://yts.am/api/v2/list_movies.json?query_term=%s' % (
                urllib.quote(search_string.encode('utf-8'))
            )

            log.debug('requesting: %s' % url)

            try:
                result = requests.get(url)
                try:
                    data = result.json()
                except ValueError:
                    log.debug('Could not decode json from response: %s', result.text)
                    raise plugin.PluginError('Error getting result from yts.')
            except requests.RequestException as e:
                raise plugin.PluginError('Could not retrieve query from yts (%s)' % e.args[0])
            if not data['status'] == 'ok':
                raise plugin.PluginError('failed to query YTS')

            try:
                if data['data']['movie_count'] > 0:
                    for item in data['data']['movies']:
                        for torrent in item['torrents']:
                            entry = Entry()
                            entry['title'] = item['title']
                            entry['year'] = item['year']
                            entry['url'] = torrent['url']
                            entry['content_size'] = parse_filesize(
                                str(torrent['size_bytes']) + "b"
                            )
                            entry['torrent_seeds'] = torrent['seeds']
                            entry['torrent_leeches'] = torrent['peers']
                            entry['torrent_info_hash'] = torrent['hash']
                            entry['torrent_availability'] = torrent_availability(
                                entry['torrent_seeds'], entry['torrent_leeches']
                            )
                            entry['quality'] = torrent['quality']
                            entry['imdb_id'] = item['imdb_code']
                            if entry.isvalid():
                                entries.add(entry)
            except Exception:
                log.debug('invalid return structure from YTS')

        log.debug('Search got %d results' % len(entries))
        return entries
Beispiel #13
0
    def _parse_torznab_attrs(self, entry, attrs):
        """Parse the torznab::attr values from the response

        https://github.com/Sonarr/Sonarr/wiki/Implementing-a-Torznab-indexer#torznab-results
        """
        dictionary = {
            'episode': {'name': 'series_episode', 'type': int},
            'imdbid': {'name': 'imdb_id', 'type': str},
            'infohash': {'name': 'torrent_info_hash', 'type': str},
            'leechers': {'name': 'torrent_leeches', 'type': int},
            'rageid': {'name': 'tvrage_id', 'type': int},
            'season': {'name': 'series_season', 'type': int},
            'seeders': {'name': 'torrent_seeds', 'type': int},
            'title': {'name': 'series_name', 'type': str},
            'tmdbid': {'name': 'tmdb_id', 'type': int},
            'traktid': {'name': 'trakt_id', 'type': int},
            'tvdbid': {'name': 'tvdb_id', 'type': int},
            'tvmazeid': {'name': 'tvmaze_series_id', 'type': int},
            'tvrageid': {'name': 'tvrage_id', 'type': int},
        }
        misc = {}
        for attr in attrs:
            name = attr.get('name')
            if name in dictionary.keys():
                entry[dictionary[name]['name']] = dictionary[name]['type'](attr.get('value'))
            elif name == 'peers':
                misc['peers'] = int(attr.get('value'))
            elif name == 'imdb':
                misc['imdb'] = str(attr.get('value'))
            elif name == 'size':
                misc['size'] = int(attr.get('value'))

        if 'imdb_id' not in entry.keys() and 'imdb' in misc.keys():
            entry['imdb_id'] = 'tt{}'.format(misc['imdb'])

        if 'peers' in misc.keys():
            if 'torrent_leeches' not in entry.keys() and 'torrent_seeds' in entry.keys():
                entry['torrent_leeches'] = misc['peers'] - entry['torrent_seeds']
            if 'torrent_leeches' in entry.keys() and 'torrent_seeds' not in entry.keys():
                entry['torrent_seeds'] = misc['peers'] - entry['torrent_leeches']

        if 'content_size' not in entry.keys() and 'size' in misc.keys():
            entry['content_size'] = misc['size'] // (2 ** 20)

        if 'torrent_seeds' in entry.keys() and 'torrent_leeches' in entry.keys():
            entry['torrent_availability'] = torrent_availability(
                entry['torrent_seeds'], entry['torrent_leeches']
            )
Beispiel #14
0
    def _parse_torznab_attrs(self, entry, attrs):
        """Parse the torznab::attr values from the response

        https://github.com/Sonarr/Sonarr/wiki/Implementing-a-Torznab-indexer#torznab-results
        """
        dictionary = {
            'episode': {'name': 'series_episode', 'type': int},
            'imdbid': {'name': 'imdb_id', 'type': str},
            'infohash': {'name': 'torrent_info_hash', 'type': str},
            'leechers': {'name': 'torrent_leeches', 'type': int},
            'rageid': {'name': 'tvrage_id', 'type': int},
            'season': {'name': 'series_season', 'type': int},
            'seeders': {'name': 'torrent_seeds', 'type': int},
            'title': {'name': 'series_name', 'type': str},
            'tmdbid': {'name': 'tmdb_id', 'type': int},
            'traktid': {'name': 'trakt_id', 'type': int},
            'tvdbid': {'name': 'tvdb_id', 'type': int},
            'tvmazeid': {'name': 'tvmaze_series_id', 'type': int},
            'tvrageid': {'name': 'tvrage_id', 'type': int}
        }
        misc = {}
        for attr in attrs:
            name = attr.get('name')
            if name in dictionary.keys():
                entry[dictionary[name]['name']] = dictionary[name]['type'](attr.get('value'))
            elif name == 'peers':
                misc['peers'] = int(attr.get('value'))
            elif name == 'imdb':
                misc['imdb'] = str(attr.get('value'))
            elif name == 'size':
                misc['size'] = int(attr.get('value'))

        if 'imdb_id' not in entry.keys() and 'imdb' in misc.keys():
            entry['imdb_id'] = 'tt{}'.format(misc['imdb'])

        if 'peers' in misc.keys():
            if 'torrent_leeches' not in entry.keys() and 'torrent_seeds' in entry.keys():
                entry['torrent_leeches'] = misc['peers'] - entry['torrent_seeds']
            if 'torrent_leeches' in entry.keys() and 'torrent_seeds' not in entry.keys():
                entry['torrent_seeds'] = misc['peers'] - entry['torrent_leeches']

        if 'content_size' not in entry.keys() and 'size' in misc.keys():
            entry['content_size'] = old_div(misc['size'], 2 ** 20)

        if 'torrent_seeds' in entry.keys() and 'torrent_leeches' in entry.keys():
            entry['torrent_availability'] = torrent_availability(
                entry['torrent_seeds'], entry['torrent_leeches']
            )
Beispiel #15
0
 def json_to_entry(self, json_result: dict) -> Entry:
     entry = Entry()
     entry['title'] = json_result['title']
     entry['torrent_seeds'] = int(json_result['swarm']['seeders'])
     entry['torrent_leeches'] = int(json_result['swarm']['leechers'])
     entry['torrent_timestamp'] = int(
         time.mktime(
             datetime.strptime(json_result['imported'],
                               '%Y-%m-%dT%H:%M:%S.%fZ').timetuple()))
     entry['torrent_availability'] = torrent_availability(
         entry['torrent_seeds'], entry['torrent_leeches'])
     entry['content_size'] = int(
         round(int(json_result['size']) /
               (1024 * 1024)))  # content_size is in MiB
     entry['torrent_info_hash'] = json_result['infohash']
     entry['url'] = json_result['magnet']
     return entry
Beispiel #16
0
    def extract_entry_from_soup(self, soup):
        table = soup.find('div', {'id': 'main_table'})
        if table is None:
            raise PluginError('Could not fetch results table from Fuzer, aborting')

        log.trace('fuzer results table: %s', table)
        table = table.find('table', {'class': 'table_info'})
        if len(table.find_all('tr')) == 1:
            log.debug('No search results were returned from Fuzer, continuing')
            return []

        entries = []
        for tr in table.find_all("tr"):
            if not tr.get('class') or 'colhead_dark' in tr.get('class'):
                continue
            name = tr.find('div', {'class': 'main_title'}).find('a').text
            torrent_name = re.search(
                '\\n(.*)', tr.find('div', {'style': 'float: right;'}).find('a')['title']
            ).group(1)
            attachment_link = tr.find('div', {'style': 'float: right;'}).find('a')['href']
            attachment_id = re.search(r'attachmentid=(\d+)', attachment_link).group(1)
            raw_size = tr.find_all('td', {'class': 'inline_info'})[0].text.strip()
            seeders = int(tr.find_all('td', {'class': 'inline_info'})[2].text)
            leechers = int(tr.find_all('td', {'class': 'inline_info'})[3].text)

            e = Entry()
            e['title'] = name
            final_url = 'https://www.fuzer.me/rss/torrent.php/{}/{}/{}/{}'.format(
                attachment_id, self.user_id, self.rss_key, torrent_name
            )

            log.debug('RSS-ified download link: %s', final_url)
            e['url'] = final_url

            e['torrent_seeds'] = seeders
            e['torrent_leeches'] = leechers
            e['torrent_availability'] = torrent_availability(
                e['torrent_seeds'], e['torrent_leeches']
            )

            size = re.search(r'(\d+(?:[.,]\d+)*)\s?([KMGTP]B)', raw_size)
            e['content_size'] = parse_filesize(size.group(0))

            entries.append(e)
        return entries
Beispiel #17
0
    def search(self, task, entry, config):
        if not isinstance(config, dict):
            config = {'category': config}
        config.setdefault('category', 'anime eng')
        config.setdefault('filter', 'all')
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            name = normalize_unicode(search_string)
            url = 'https://www.nyaa.si/?page=rss&q=%s&c=%s&f=%s' % (
                quote(name.encode('utf-8')),
                CATEGORIES[config['category']],
                FILTERS.index(config['filter']),
            )

            log.debug('requesting: %s' % url)
            rss = feedparser.parse(url)

            status = rss.get('status', False)
            if status != 200:
                log.debug('Search result not 200 (OK), received %s' % status)
            if status >= 400:
                continue

            ex = rss.get('bozo_exception', False)
            if ex:
                log.error('Got bozo_exception (bad feed) on %s' % url)
                continue

            for item in rss.entries:
                entry = Entry()
                entry['title'] = item.title
                entry['url'] = item.link
                entry['torrent_seeds'] = int(item.nyaa_seeders)
                entry['torrent_leeches'] = int(item.nyaa_leechers)
                entry['torrent_info_hash'] = item.nyaa_infohash
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                if item.nyaa_size:
                    entry['content_size'] = parse_filesize(item.nyaa_size)

                entries.add(entry)

        return entries
Beispiel #18
0
    def search(self, task, entry, config):
        if not isinstance(config, dict):
            config = {'category': config}
        config.setdefault('category', 'anime eng')
        config.setdefault('filter', 'all')
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            name = normalize_unicode(search_string)
            url = 'https://www.nyaa.si/?page=rss&q=%s&c=%s&f=%s' % (
                quote(name.encode('utf-8')),
                CATEGORIES[config['category']],
                FILTERS.index(config['filter']),
            )

            log.debug('requesting: %s' % url)
            rss = feedparser.parse(url)

            status = rss.get('status', False)
            if status != 200:
                log.debug('Search result not 200 (OK), received %s' % status)
            if status >= 400:
                continue

            ex = rss.get('bozo_exception', False)
            if ex:
                log.error('Got bozo_exception (bad feed) on %s' % url)
                continue

            for item in rss.entries:
                entry = Entry()
                entry['title'] = item.title
                entry['url'] = item.link
                entry['torrent_seeds'] = int(item.nyaa_seeders)
                entry['torrent_leeches'] = int(item.nyaa_leechers)
                entry['torrent_info_hash'] = item.nyaa_infohash
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches'])
                if item.nyaa_size:
                    entry['content_size'] = parse_filesize(item.nyaa_size)

                entries.add(entry)

        return entries
Beispiel #19
0
    def search(self, task, entry, config=None):
        """
        Search for name from iptorrents
        """

        categories = config.get('category', 'All')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]

        # If there are any text categories, turn them into their id number
        categories = [c if isinstance(c, int) else CATEGORIES[c] for c in categories]
        filter_url = '&'.join((str(c) + '=') for c in categories)

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string)
            query = quote_plus(query.encode('utf8'))

            url = "{base_url}/t?{filter}&q={query}&qf=".format(
                base_url=BASE_URL, filter=filter_url, query=query
            )
            log.debug('searching with url: %s' % url)
            req = requests.get(
                url, cookies={'uid': str(config['uid']), 'pass': config['password']}
            )

            if '/u/' + str(config['uid']) not in req.text:
                raise plugin.PluginError("Invalid cookies (user not logged in)...")

            soup = get_soup(req.content, parser="html.parser")
            torrents = soup.find('table', {'id': 'torrents'})

            results = torrents.findAll('tr')
            for torrent in results:
                if torrent.th and 'ac' in torrent.th.get('class'):
                    # Header column
                    continue
                if torrent.find('td', {'colspan': '99'}):
                    log.debug('No results found for search %s', search_string)
                    break
                entry = Entry()
                link = torrent.find('a', href=re.compile('download'))['href']
                entry['url'] = "{base}{link}?torrent_pass={key}".format(
                    base=BASE_URL, link=link, key=config.get('rss_key')
                )
                entry['title'] = torrent.find('a', href=re.compile('details')).text

                seeders = torrent.findNext('td', {'class': 'ac t_seeders'}).text
                leechers = torrent.findNext('td', {'class': 'ac t_leechers'}).text
                entry['torrent_seeds'] = int(seeders)
                entry['torrent_leeches'] = int(leechers)
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )

                size = torrent.findNext(text=re.compile(r'^([\.\d]+) ([GMK]?)B$'))
                size = re.search(r'^([\.\d]+) ([GMK]?)B$', size)

                entry['content_size'] = parse_filesize(size.group(0))
                log.debug('Found entry %s', entry)
                entries.add(entry)

        return entries
Beispiel #20
0
    def search(self, task, entry, config=None):
        """
        Search for name from torrentleech.
        """
        request_headers = {'User-Agent': 'curl/7.54.0'}
        rss_key = config['rss_key']

        # build the form request:
        data = {'username': config['username'], 'password': config['password']}
        # POST the login form:
        try:
            login = task.requests.post(
                'https://www.torrentleech.org/user/account/login/',
                data=data,
                headers=request_headers,
                allow_redirects=True,
            )
        except RequestException as e:
            raise PluginError('Could not connect to torrentleech: %s' % str(e))

        if login.url.endswith('/user/account/login/'):
            raise PluginError(
                'Could not login to torrentleech, faulty credentials?')

        if not isinstance(config, dict):
            config = {}
            # sort = SORT.get(config.get('sort_by', 'seeds'))
            # if config.get('sort_reverse'):
            # sort += 1
        categories = config.get('category', 'all')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]
        # If there are any text categories, turn them into their id number
        categories = [
            c if isinstance(c, int) else CATEGORIES[c] for c in categories
        ]
        filter_url = '/categories/{}'.format(','.join(
            str(c) for c in categories))
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string).replace(":", "")
            # urllib.quote will crash if the unicode string has non ascii characters,
            # so encode in utf-8 beforehand

            url = ('https://www.torrentleech.org/torrents/browse/list/query/' +
                   quote(query.encode('utf-8')) + filter_url)
            log.debug('Using %s as torrentleech search url', url)

            results = task.requests.get(url,
                                        headers=request_headers,
                                        cookies=login.cookies).json()

            for torrent in results['torrentList']:
                entry = Entry()
                entry['download_headers'] = request_headers
                entry['title'] = torrent['name']

                # construct download URL
                torrent_url = 'https://www.torrentleech.org/rss/download/{}/{}/{}'.format(
                    torrent['fid'], rss_key, torrent['filename'])
                log.debug('RSS-ified download link: %s', torrent_url)
                entry['url'] = torrent_url

                # seeders/leechers
                entry['torrent_seeds'] = torrent['seeders']
                entry['torrent_leeches'] = torrent['leechers']
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches'])
                entry['content_size'] = parse_filesize(
                    str(torrent['size']) + ' b')
                entries.add(entry)

        return sorted(entries,
                      reverse=True,
                      key=lambda x: x.get('torrent_availability'))
Beispiel #21
0
    def search(self, task, entry, config):
        """
            Search for entries on 1337x
        """

        if not isinstance(config, dict):
            config = {}

        order_by = ''
        sort_order = ''
        if isinstance(config.get('order_by'), str):
            if config['order_by'] != 'leechers':
                order_by = '/{0}/desc'.format(config['order_by'])
                sort_order = 'sort-'

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):

            query = '{0}search/{1}{2}/1/'.format(
                sort_order, quote(search_string.encode('utf8')), order_by
            )
            log.debug(
                'Using search params: %s; ordering by: %s', search_string, order_by or 'default'
            )
            try:
                page = task.requests.get(self.base_url + query)
                log.debug('requesting: %s', page.url)
            except RequestException as e:
                log.error('1337x request failed: %s', e)
                continue

            soup = get_soup(page.content)
            if soup.find('div', attrs={'class': 'table-list-wrap'}) is not None:
                for link in soup.find('div', attrs={'class': 'table-list-wrap'}).findAll(
                    'a', href=re.compile('^/torrent/')
                ):

                    li = link.parent.parent

                    title = str(link.text).replace('...', '')
                    info_url = self.base_url + str(link.get('href'))[1:]
                    seeds = int(li.find('td', class_='seeds').string)
                    leeches = int(li.find('td', class_='leeches').string)
                    size = str(li.find('td', class_='coll-4').contents[0])

                    size = parse_filesize(size)

                    e = Entry()

                    e['url'] = info_url
                    e['title'] = title
                    e['torrent_seeds'] = seeds
                    e['torrent_leeches'] = leeches
                    e['torrent_availability'] = torrent_availability(
                        e['torrent_seeds'], e['torrent_leeches']
                    )
                    e['content_size'] = size

                    entries.add(e)

        return entries
Beispiel #22
0
    def search(self, task, entry, config=None):
        """
        Search for name from torrentday.
        """

        categories = config.get('category', 'all')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]
        # If there are any text categories, turn them into their id number
        categories = [
            c if isinstance(c, int) else CATEGORIES[c] for c in categories
        ]
        params = {
            'cata': 'yes',
            'c{}'.format(','.join(str(c) for c in categories)): 1,
            'clear-new': 1,
        }
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):

            url = 'https://www.torrentday.com/t'
            params['q'] = normalize_unicode(search_string).replace(':', '')
            cookies = {
                'uid': config['uid'],
                'pass': config['passkey'],
                '__cfduid': config['cfduid'],
            }

            try:
                page = requests.get(url, params=params,
                                    cookies=cookies).content
            except RequestException as e:
                raise PluginError(
                    'Could not connect to torrentday: {}'.format(e))

            # the following should avoid table being None due to a malformed
            # html in td search results
            soup = get_soup(page).contents[1].contents[1].next.next.nextSibling
            table = soup.find('table', {'id': 'torrentTable'})
            if table is None:
                raise PluginError(
                    'Search returned by torrentday appears to be empty or malformed.'
                )

            # the first row is the header so skip it
            for tr in table.find_all('tr')[1:]:
                entry = Entry()
                # find the torrent names
                td = tr.find('td', {'class': 'torrentNameInfo'})
                if not td:
                    log.warning('Could not find entry torrentNameInfo for %s.',
                                search_string)
                    continue
                title = td.find('a')
                if not title:
                    log.warning('Could not determine title for %s.',
                                search_string)
                    continue
                entry['title'] = title.contents[0]
                log.debug('title: %s', title.contents[0])

                # find download link
                torrent_url = tr.find('td', {'class': 'ac'})
                if not torrent_url:
                    log.warning('Could not determine download link for %s.',
                                search_string)
                    continue
                torrent_url = torrent_url.find('a').get('href')

                # construct download URL
                torrent_url = ('https://www.torrentday.com/' + torrent_url +
                               '?torrent_pass='******'rss_key'])
                log.debug('RSS-ified download link: %s', torrent_url)
                entry['url'] = torrent_url

                # us tr object for seeders/leechers
                seeders = tr.find('td', {'class': 'ac seedersInfo'})
                leechers = tr.find('td', {'class': 'ac leechersInfo'})
                entry['torrent_seeds'] = int(seeders.contents[0].replace(
                    ',', ''))
                entry['torrent_leeches'] = int(leechers.contents[0].replace(
                    ',', ''))
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches'])

                # use tr object for size
                size = tr.find(
                    'td',
                    text=re.compile(r'([\.\d]+) ([TGMKk]?)B')).contents[0]
                size = re.search(r'([\.\d]+) ([TGMKk]?)B', str(size))

                entry['content_size'] = parse_filesize(size.group(0))

                entries.add(entry)

        return sorted(entries,
                      reverse=True,
                      key=lambda x: x.get('torrent_availability'))
Beispiel #23
0
    def entries_from_search(self, name, url=None):
        """Parses torrent download url from search results"""
        name = normalize_unicode(name)
        if not url:
            url = 'http://www.newtorrents.info/search/%s' % quote(
                name.encode('utf-8'), safe=b':/~?=&%')

        log.debug('search url: %s' % url)

        html = requests.get(url).text
        # fix </SCR'+'IPT> so that BS does not crash
        # TODO: should use beautifulsoup massage
        html = re.sub(r'(</SCR.*?)...(.*?IPT>)', r'\1\2', html)

        soup = get_soup(html)
        # saving torrents in dict
        torrents = []
        for link in soup.find_all('a', attrs={'href': re.compile('down.php')}):
            torrent_url = 'http://www.newtorrents.info%s' % link.get('href')
            release_name = link.parent.next.get('title')
            # quick dirty hack
            seed = link.find_next('td', attrs={
                'class': re.compile('s')
            }).renderContents()
            if seed == 'n/a':
                seed = 0
            else:
                try:
                    seed = int(seed)
                except ValueError:
                    log.warning(
                        'Error converting seed value (%s) from newtorrents to integer.'
                        % seed)
                    seed = 0

            # TODO: also parse content_size and peers from results
            torrents.append(
                Entry(
                    title=release_name,
                    url=torrent_url,
                    torrent_seeds=seed,
                    torrent_availability=torrent_availability(seed, 0),
                ))
        # sort with seed number Reverse order
        torrents.sort(reverse=True,
                      key=lambda x: x.get('torrent_availability', 0))
        # choose the torrent
        if not torrents:
            dashindex = name.rfind('-')
            if dashindex != -1:
                return self.entries_from_search(name[:dashindex])
            else:
                return torrents
        else:
            if len(torrents) == 1:
                log.debug('found only one matching search result.')
            else:
                log.debug(
                    'search result contains multiple matches, sorted %s by most seeders'
                    % torrents)
            return torrents
Beispiel #24
0
    def search(self, task, entry, config=None):
        """
        Search for name from torrentday.
        """

        categories = config.get('category', 'all')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]
        # If there are any text categories, turn them into their id number
        categories = [c if isinstance(c, int) else CATEGORIES[c] for c in categories]
        params = {
            'cata': 'yes',
            'c{}'.format(','.join(str(c) for c in categories)): 1,
            'clear-new': 1,
        }
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):

            url = 'https://www.torrentday.com/t'
            params['q'] = normalize_unicode(search_string).replace(':', '')
            cookies = {
                'uid': config['uid'],
                'pass': config['passkey'],
                '__cfduid': config['cfduid'],
            }

            try:
                page = requests.get(url, params=params, cookies=cookies).content
            except RequestException as e:
                raise PluginError('Could not connect to torrentday: {}'.format(e))

            # the following should avoid table being None due to a malformed
            # html in td search results
            soup = get_soup(page).contents[1].contents[1].next.next.nextSibling
            table = soup.find('table', {'id': 'torrentTable'})
            if table is None:
                raise PluginError(
                    'Search returned by torrentday appears to be empty or malformed.'
                )

            # the first row is the header so skip it
            for tr in table.find_all('tr')[1:]:
                entry = Entry()
                # find the torrent names
                td = tr.find('td', {'class': 'torrentNameInfo'})
                if not td:
                    log.warning('Could not find entry torrentNameInfo for %s.', search_string)
                    continue
                title = td.find('a')
                if not title:
                    log.warning('Could not determine title for %s.', search_string)
                    continue
                entry['title'] = title.contents[0]
                log.debug('title: %s', title.contents[0])

                # find download link
                torrent_url = tr.find('td', {'class': 'ac'})
                if not torrent_url:
                    log.warning('Could not determine download link for %s.', search_string)
                    continue
                torrent_url = torrent_url.find('a').get('href')

                # construct download URL
                torrent_url = (
                    'https://www.torrentday.com/'
                    + torrent_url
                    + '?torrent_pass='******'rss_key']
                )
                log.debug('RSS-ified download link: %s', torrent_url)
                entry['url'] = torrent_url

                # us tr object for seeders/leechers
                seeders = tr.find('td', {'class': 'ac seedersInfo'})
                leechers = tr.find('td', {'class': 'ac leechersInfo'})
                entry['torrent_seeds'] = int(seeders.contents[0].replace(',', ''))
                entry['torrent_leeches'] = int(leechers.contents[0].replace(',', ''))
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )

                # use tr object for size
                size = tr.find('td', text=re.compile(r'([\.\d]+) ([TGMKk]?)B')).contents[0]
                size = re.search(r'([\.\d]+) ([TGMKk]?)B', str(size))

                entry['content_size'] = parse_filesize(size.group(0))

                entries.add(entry)

        return sorted(entries, reverse=True, key=lambda x: x.get('torrent_availability'))
Beispiel #25
0
    def search(self, task, entry, config):
        task.requests.add_domain_limiter(self.request_limiter)
        config = self.prepare_config(config)
        api_key = config['api_key']

        searches = entry.get('search_strings', [entry['title']])

        if 'series_name' in entry:
            if entry.get('season_pack_lookup', False):
                search = {'category': 'Season'}
            else:
                search = {'category': 'Episode'}
            if config.get('origin'):
                search['origin'] = config['origin']
            if 'tvdb_id' in entry:
                search['tvdb'] = entry['tvdb_id']
            elif 'tvrage_id' in entry:
                search['tvrage'] = entry['tvrage_id']
            else:
                search['series'] = entry['series_name']
            if entry.get('season_pack_lookup', False) and 'series_season' in entry:
                search['name'] = 'Season %s' % entry['series_season']
            elif 'series_id' in entry:
                # BTN wants an ep style identifier even for sequence shows
                if entry.get('series_id_type') == 'sequence':
                    search['name'] = 'S01E%02d' % entry['series_id']
                else:
                    search['name'] = (
                        entry['series_id'] + '%'
                    )  # added wildcard search for better results.
            searches = [search]
            # If searching by series name ending in a parenthetical, try again without it if there are no results.
            if search.get('series') and search['series'].endswith(')'):
                match = re.match(r'(.+)\([^\(\)]+\)$', search['series'])
                if match:
                    searches.append(dict(search, series=match.group(1).strip()))

        results = set()
        for search in searches:
            data = json.dumps({'method': 'getTorrents', 'params': [api_key, search], 'id': 1})
            try:
                r = task.requests.post(
                    'https://api.broadcasthe.net/',
                    data=data,
                    headers={'Content-type': 'application/json'},
                )
            except requests.RequestException as e:
                log.error('Error searching btn: %s' % e)
                continue
            try:
                content = r.json()
            except ValueError as e:
                raise plugin.PluginError('Error searching btn. Maybe it\'s down?. %s' % str(e))
            if not content or not content['result']:
                log.debug('No results from btn')
                if content and content.get('error'):
                    if content['error'].get('code') == -32002:
                        log.error('btn api call limit exceeded, throttling connection rate')
                        self.request_limiter.tokens = -1
                    else:
                        log.error(
                            'Error searching btn: %s'
                            % content['error'].get('message', content['error'])
                        )
                continue
            if 'torrents' in content['result']:
                for item in content['result']['torrents'].values():
                    entry = Entry()
                    entry['title'] = item['ReleaseName']
                    if config['append_quality']:
                        entry['title'] += ' '.join(
                            ['', item['Resolution'], item['Source'], item['Codec']]
                        )
                    entry['url'] = item['DownloadURL']
                    entry['torrent_seeds'] = int(item['Seeders'])
                    entry['torrent_leeches'] = int(item['Leechers'])
                    entry['torrent_info_hash'] = item['InfoHash']
                    entry['torrent_availability'] = torrent_availability(
                        entry['torrent_seeds'], entry['torrent_leeches']
                    )
                    entry['btn_origin'] = item['Origin']
                    if item['TvdbID'] and int(item['TvdbID']):
                        entry['tvdb_id'] = int(item['TvdbID'])
                    if item['TvrageID'] and int(item['TvrageID']):
                        entry['tvrage_id'] = int(item['TvrageID'])
                    results.add(entry)
                # Don't continue searching if this search yielded results
                break
        return results
Beispiel #26
0
    def search(self, task, entry, config):
        """
            Search for entries on Limetorrents
        """

        if not isinstance(config, dict):
            config = {'category': config}

        order_by = ''
        if isinstance(config.get('order_by'), str):
            if config['order_by'] != 'date':
                order_by = '{0}/1'.format(config['order_by'])

        category = 'all'
        if isinstance(config.get('category'), str):
            category = '{0}'.format(config['category'])

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):
            # No special characters - use dashes instead of %20
            cleaned_search_string = clean_symbols(search_string).replace(
                ' ', '-')

            query = 'search/{0}/{1}/{2}'.format(
                category, cleaned_search_string.encode('utf8'), order_by)
            logger.debug(
                'Using search: {}; category: {}; ordering: {}',
                cleaned_search_string,
                category,
                order_by or 'default',
            )
            try:
                page = task.requests.get(self.base_url + query)
                logger.debug('requesting: {}', page.url)
            except RequestException as e:
                logger.error('Limetorrents request failed: {}', e)
                continue

            soup = get_soup(page.content)
            if soup.find('a', attrs={'class': 'csprite_dl14'}) is not None:
                for link in soup.findAll('a', attrs={'class': 'csprite_dl14'}):

                    row = link.find_parent('tr')
                    info_url = str(link.get('href'))

                    # Get the title from the URL as it's complete versus the actual Title text which gets cut off
                    title = str(link.next_sibling.get('href'))
                    title = title[:title.rfind('-torrent')].replace('-', ' ')
                    title = title[1:]

                    data = row.findAll('td', attrs={'class': 'tdnormal'})
                    size = str(data[1].text).replace(',', '')

                    seeds = int(
                        row.find('td', attrs={
                            'class': 'tdseed'
                        }).text.replace(',', ''))
                    leeches = int(
                        row.find('td', attrs={
                            'class': 'tdleech'
                        }).text.replace(',', ''))

                    size = parse_filesize(size)

                    e = Entry()

                    e['url'] = info_url
                    e['title'] = title
                    e['torrent_seeds'] = seeds
                    e['torrent_leeches'] = leeches
                    e['torrent_availability'] = torrent_availability(
                        e['torrent_seeds'], e['torrent_leeches'])
                    e['content_size'] = size

                    entries.add(e)

        return entries
Beispiel #27
0
    def search(self, task, entry, config):
        """
            Search for entries on 1337x
        """

        if not isinstance(config, dict):
            config = {}

        order_by = ''
        sort_order = ''
        if isinstance(config.get('order_by'), str):
            if config['order_by'] != 'leechers':
                order_by = '/{0}/desc'.format(config['order_by'])
                sort_order = 'sort-'

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):

            query = '{0}search/{1}{2}/1/'.format(
                sort_order, quote(search_string.encode('utf8')), order_by
            )
            log.debug(
                'Using search params: %s; ordering by: %s', search_string, order_by or 'default'
            )
            try:
                page = task.requests.get(self.base_url + query)
                log.debug('requesting: %s', page.url)
            except RequestException as e:
                log.error('1337x request failed: %s', e)
                continue

            soup = get_soup(page.content)
            if soup.find('div', attrs={'class': 'table-list-wrap'}) is not None:
                for link in soup.find('div', attrs={'class': 'table-list-wrap'}).findAll(
                    'a', href=re.compile('^/torrent/')
                ):
                    li = link.parent.parent

                    title = str(link.text).replace('...', '')
                    info_url = self.base_url + str(link.get('href'))[1:]
                    seeds = int(li.find('td', class_='seeds').string)
                    leeches = int(li.find('td', class_='leeches').string)
                    size = str(li.find('td', class_='coll-4').contents[0])

                    size = parse_filesize(size)

                    e = Entry()

                    e['url'] = info_url
                    e['title'] = title
                    e['torrent_seeds'] = seeds
                    e['torrent_leeches'] = leeches
                    e['torrent_availability'] = torrent_availability(
                        e['torrent_seeds'], e['torrent_leeches']
                    )
                    e['content_size'] = size

                    entries.add(e)

        return entries
Beispiel #28
0
    def search(self, task, entry, config):
        """
            Search for entries on Limetorrents
        """

        if not isinstance(config, dict):
            config = {'category': config}

        order_by = ''
        if isinstance(config.get('order_by'), str):
            if config['order_by'] != 'date':
                order_by = '{0}/1'.format(config['order_by'])

        category = 'all'
        if isinstance(config.get('category'), str):
            category = '{0}'.format(config['category'])

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):
            # No special characters - use dashes instead of %20
            cleaned_search_string = clean_symbols(search_string).replace(' ', '-')

            query = 'search/{0}/{1}/{2}'.format(
                category, cleaned_search_string.encode('utf8'), order_by
            )
            log.debug(
                'Using search: %s; category: %s; ordering: %s',
                cleaned_search_string,
                category,
                order_by or 'default',
            )
            try:
                page = task.requests.get(self.base_url + query)
                log.debug('requesting: %s', page.url)
            except RequestException as e:
                log.error('Limetorrents request failed: %s', e)
                continue

            soup = get_soup(page.content)
            if soup.find('a', attrs={'class': 'csprite_dl14'}) is not None:
                for link in soup.findAll('a', attrs={'class': 'csprite_dl14'}):

                    row = link.find_parent('tr')
                    info_url = str(link.get('href'))

                    # Get the title from the URL as it's complete versus the actual Title text which gets cut off
                    title = str(link.next_sibling.get('href'))
                    title = title[: title.rfind('-torrent')].replace('-', ' ')
                    title = title[1:]

                    data = row.findAll('td', attrs={'class': 'tdnormal'})
                    size = str(data[1].text).replace(',', '')

                    seeds = int(row.find('td', attrs={'class': 'tdseed'}).text.replace(',', ''))
                    leeches = int(row.find('td', attrs={'class': 'tdleech'}).text.replace(',', ''))

                    size = parse_filesize(size)

                    e = Entry()

                    e['url'] = info_url
                    e['title'] = title
                    e['torrent_seeds'] = seeds
                    e['torrent_leeches'] = leeches
                    e['torrent_availability'] = torrent_availability(
                        e['torrent_seeds'], e['torrent_leeches']
                    )
                    e['content_size'] = size

                    entries.add(e)

        return entries
Beispiel #29
0
    def search(self, task, entry, config=None):
        """
        Search for name from iptorrents
        """

        categories = config.get('category', 'All')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]

        # If there are any text categories, turn them into their id number
        categories = [
            c if isinstance(c, int) else CATEGORIES[c] for c in categories
        ]
        category_params = {str(c): '' for c in categories if str(c)}

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):
            search_params = {
                key: value
                for (key, value) in category_params.items()
            }

            query = normalize_unicode(search_string)
            search_params.update({'q': query, 'qf': ''})

            logger.debug('searching with params: {}', search_params)
            if config.get('free'):
                req = requests.get(FREE_SEARCH_URL,
                                   params=search_params,
                                   cookies={
                                       'uid': str(config['uid']),
                                       'pass': config['password']
                                   })
            else:
                req = requests.get(SEARCH_URL,
                                   params=search_params,
                                   cookies={
                                       'uid': str(config['uid']),
                                       'pass': config['password']
                                   })
            logger.debug('full search URL: {}', req.url)

            if '/u/' + str(config['uid']) not in req.text:
                raise plugin.PluginError(
                    "Invalid cookies (user not logged in)...")

            soup = get_soup(req.content, parser="html.parser")
            torrents = soup.find('table', {'id': 'torrents'})

            results = torrents.findAll('tr')
            for torrent in results:
                if torrent.th and 'ac' in torrent.th.get('class'):
                    # Header column
                    continue
                if torrent.find('td', {'colspan': '99'}):
                    logger.debug('No results found for search {}',
                                 search_string)
                    break
                entry = Entry()
                link = torrent.find('a', href=re.compile('download'))['href']
                entry[
                    'url'] = f"{BASE_URL}{link}?torrent_pass={config.get('rss_key')}"
                entry['title'] = torrent.find('a',
                                              href=re.compile('details')).text

                seeders = torrent.findNext('td', {
                    'class': 'ac t_seeders'
                }).text
                leechers = torrent.findNext('td', {
                    'class': 'ac t_leechers'
                }).text
                entry['torrent_seeds'] = int(seeders)
                entry['torrent_leeches'] = int(leechers)
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches'])

                size = torrent.findNext(
                    text=re.compile(r'^([\.\d]+) ([GMK]?)B$'))
                size = re.search(r'^([\.\d]+) ([GMK]?)B$', size)

                entry['content_size'] = parse_filesize(size.group(0))
                logger.debug('Found entry {}', entry)
                entries.add(entry)

        return entries
Beispiel #30
0
    def search(self, task, entry, config=None):
        """
        Search for name from iptorrents
        """

        categories = config.get('category', 'All')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]

        # If there are any text categories, turn them into their id number
        categories = [
            c if isinstance(c, int) else CATEGORIES[c] for c in categories
        ]
        filter_url = '&'.join((str(c) + '=') for c in categories)

        entries = set()

        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string)
            query = quote_plus(query.encode('utf8'))

            url = "{base_url}/t?{filter}&q={query}&qf=".format(
                base_url=BASE_URL, filter=filter_url, query=query)
            logger.debug('searching with url: {}', url)
            req = requests.get(url,
                               cookies={
                                   'uid': str(config['uid']),
                                   'pass': config['password']
                               })

            if '/u/' + str(config['uid']) not in req.text:
                raise plugin.PluginError(
                    "Invalid cookies (user not logged in)...")

            soup = get_soup(req.content, parser="html.parser")
            torrents = soup.find('table', {'id': 'torrents'})

            results = torrents.findAll('tr')
            for torrent in results:
                if torrent.th and 'ac' in torrent.th.get('class'):
                    # Header column
                    continue
                if torrent.find('td', {'colspan': '99'}):
                    logger.debug('No results found for search {}',
                                 search_string)
                    break
                entry = Entry()
                link = torrent.find('a', href=re.compile('download'))['href']
                entry['url'] = "{base}{link}?torrent_pass={key}".format(
                    base=BASE_URL, link=link, key=config.get('rss_key'))
                entry['title'] = torrent.find('a',
                                              href=re.compile('details')).text

                seeders = torrent.findNext('td', {
                    'class': 'ac t_seeders'
                }).text
                leechers = torrent.findNext('td', {
                    'class': 'ac t_leechers'
                }).text
                entry['torrent_seeds'] = int(seeders)
                entry['torrent_leeches'] = int(leechers)
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches'])

                size = torrent.findNext(
                    text=re.compile(r'^([\.\d]+) ([GMK]?)B$'))
                size = re.search(r'^([\.\d]+) ([GMK]?)B$', size)

                entry['content_size'] = parse_filesize(size.group(0))
                logger.debug('Found entry {}', entry)
                entries.add(entry)

        return entries
Beispiel #31
0
    def search(self, task, entry, config=None):
        """
        Search for name from torrentleech.
        """
        request_headers = {'User-Agent': 'curl/7.54.0'}
        rss_key = config['rss_key']

        # build the form request:
        data = {'username': config['username'], 'password': config['password']}
        # POST the login form:
        try:
            login = task.requests.post(
                'https://www.torrentleech.org/user/account/login/',
                data=data,
                headers=request_headers,
                allow_redirects=True,
            )
        except RequestException as e:
            raise PluginError('Could not connect to torrentleech: %s' % str(e))

        if login.url.endswith('/user/account/login/'):
            raise PluginError('Could not login to torrentleech, faulty credentials?')

        if not isinstance(config, dict):
            config = {}
            # sort = SORT.get(config.get('sort_by', 'seeds'))
            # if config.get('sort_reverse'):
            # sort += 1
        categories = config.get('category', 'all')
        # Make sure categories is a list
        if not isinstance(categories, list):
            categories = [categories]
        # If there are any text categories, turn them into their id number
        categories = [c if isinstance(c, int) else CATEGORIES[c] for c in categories]
        filter_url = '/categories/{}'.format(','.join(str(c) for c in categories))
        entries = set()
        for search_string in entry.get('search_strings', [entry['title']]):
            query = normalize_unicode(search_string).replace(":", "")
            # urllib.quote will crash if the unicode string has non ascii characters,
            # so encode in utf-8 beforehand

            url = (
                'https://www.torrentleech.org/torrents/browse/list/query/'
                + quote(query.encode('utf-8'))
                + filter_url
            )
            log.debug('Using %s as torrentleech search url', url)

            results = task.requests.get(url, headers=request_headers, cookies=login.cookies).json()

            for torrent in results['torrentList']:
                entry = Entry()
                entry['download_headers'] = request_headers
                entry['title'] = torrent['name']

                # construct download URL
                torrent_url = 'https://www.torrentleech.org/rss/download/{}/{}/{}'.format(
                    torrent['fid'], rss_key, torrent['filename']
                )
                log.debug('RSS-ified download link: %s', torrent_url)
                entry['url'] = torrent_url

                # seeders/leechers
                entry['torrent_seeds'] = torrent['seeders']
                entry['torrent_leeches'] = torrent['leechers']
                entry['torrent_availability'] = torrent_availability(
                    entry['torrent_seeds'], entry['torrent_leeches']
                )
                entry['content_size'] = parse_filesize(str(torrent['size']) + ' b')
                entries.add(entry)

        return sorted(entries, reverse=True, key=lambda x: x.get('torrent_availability'))
Beispiel #32
0
    def search(self, task, entry, config):
        """Search for entries on HEBits"""
        passkey = self.authenticate(config)
        params = {}

        if 'category' in config:
            params['cata'] = HEBitsCategory[config['category']].value

        entries = set()
        params['sort'] = HEBitsSort[config['order_by']].value
        params['type'] = 'desc' if config['order_desc'] else 'asc'
        for value in ('free', 'double', 'triple', 'pack'):
            if config.get(value):
                params[value] = 'on'

        for search_string in entry.get('search_strings', [entry['title']]):
            params['search'] = search_string
            logger.debug('Using search params: {}', params)
            try:
                page = requests.get(self.search_url, params=params)
                page.raise_for_status()
            except RequestException as e:
                logger.error('HEBits request failed: {}', e)
                continue
            soup = get_soup(page.content)
            table = first(soup.select("div.browse"), None)
            if not table:
                logger.debug(
                    'Could not find any results matching {} using the requested params {}',
                    search_string,
                    params,
                )
                continue

            all_results = table.select(
                "div.lineBrown, div.lineGray, div.lineBlue, div.lineGreen")
            if not all_results:
                raise plugin.PluginError(
                    'Result table found but not with any known items, layout change?'
                )

            for result in all_results:
                torrent_id = first(result.select(
                    'a[href^=download]')).attrs['href'].split('=')[-1]
                seeders = int(first(result.select("div.bUping")).text)
                leechers = int(first(result.select("div.bDowning")).text)

                size_strings = list(first(result.select("div.bSize")).strings)
                size_text = f'{size_strings[1]}{size_strings[2]}'
                size = parse_filesize(size_text)

                title = first(
                    result.select('a > b')).text.split("/")[-1].strip()
                images = result.select("span > img")
                freeleech, double_up, triple_up = self._fetch_bonus(images)
                req = Request('GET',
                              url=self.download_url,
                              params={
                                  'passkey': passkey,
                                  'id': torrent_id
                              }).prepare()

                entry = Entry(
                    torrent_seeds=seeders,
                    torrent_leeches=leechers,
                    torrent_availability=torrent_availability(
                        seeders, leechers),
                    content_size=size,
                    title=title,
                    freeleech=freeleech,
                    triple_up=triple_up,
                    double_up=double_up,
                    url=req.url,
                )
                entries.add(entry)

        return entries