Skip to content

Commit

Permalink
Merge pull request #649 from pymedusa/add-zooqle
Browse files Browse the repository at this point in the history
Add Zooqle torrent provider, add back BITHDTV icon and clean up BITHDTV
  • Loading branch information
labrys committed Jun 1, 2016
2 parents 5230b2d + 07a38c1 commit 3e0c619
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 55 deletions.
Binary file added gui/slick/images/providers/bithdtv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gui/slick/images/providers/zooqle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions sickbeard/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, hounddawgs, speedcd, nyaatorrents, bluetigers, xthor, abnormal, torrentbytes, cpasbien,\
freshontv, morethantv, t411, tokyotoshokan, shazbat, rarbg, alpharatio, tntvillage, binsearch, torrentproject, extratorrent, \
scenetime, btdigg, transmitthenet, tvchaosuk, bitcannon, pretome, gftracker, hdspace, newpct, elitetorrent, bitsnoop, danishbits, hd4free, limetorrents, \
norbits, ilovetorrents, sceneelite, anizb, bithdtv
norbits, ilovetorrents, sceneelite, anizb, bithdtv, zooqle

__all__ = [
'womble', 'btn', 'thepiratebay', 'kat', 'torrentleech', 'scc', 'hdtorrents',
Expand All @@ -36,7 +36,7 @@
'xthor', 'abnormal', 'scenetime', 'btdigg', 'transmitthenet', 'tvchaosuk',
'torrentproject', 'extratorrent', 'bitcannon', 'torrentz', 'pretome', 'gftracker',
'hdspace', 'newpct', 'elitetorrent', 'bitsnoop', 'danishbits', 'hd4free', 'limetorrents',
'norbits', 'ilovetorrents', 'sceneelite', 'anizb', 'bithdtv'
'norbits', 'ilovetorrents', 'sceneelite', 'anizb', 'bithdtv', 'zooqle'
]


Expand Down
120 changes: 67 additions & 53 deletions sickbeard/providers/bithdtv.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
# You should have received a copy of the GNU General Public License
# along with Medusa. If not, see <http://www.gnu.org/licenses/>.

import re
from __future__ import unicode_literals

from requests.compat import urljoin
from requests.utils import dict_from_cookiejar

from sickbeard import logger, tvcache
Expand All @@ -31,7 +33,7 @@ class BithdtvProvider(TorrentProvider): # pylint: disable=too-many-instance-att
def __init__(self):

# Provider Init
TorrentProvider.__init__(self, "BITHDTV")
TorrentProvider.__init__(self, 'BITHDTV')

# Credentials
self.username = None
Expand All @@ -45,90 +47,73 @@ def __init__(self):
# URLs
self.url = 'https://www.bit-hdtv.com/'
self.urls = {
'login': self.url + 'takelogin.php',
'search': self.url + 'torrents.php',
'login': urljoin(self.url, 'takelogin.php'),
'search': urljoin(self.url, 'torrents.php'),
}

# Proper Strings

# Cache
self.cache = tvcache.TVCache(self, min_time=10) # Only poll BitHDTV every 10 minutes max

def login(self):
"""Login method used for logging in before doing search and torrent downloads"""
if any(dict_from_cookiejar(self.session.cookies).values()):
return True

login_params = {
'username': self.username.encode('utf-8'),
'password': self.password.encode('utf-8'),
}

response = self.get_url(self.urls['login'], post_data=login_params, returns='text')
if not response:
logger.log(u"Unable to connect to provider", logger.WARNING)
self.session.cookies.clear()
return False

if '<h2>Login failed!</h2>' in response:
logger.log(u"Invalid username or password. Check your settings", logger.WARNING)
self.session.cookies.clear()
return False

return True

def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-locals, too-many-branches
"""BIT HDTV login method
"""
BIT HDTV search and parsing
@param search_string: A dict with mode (key) and the search value (value)
@param age: Not used
@param ep_obj: Not used
@return: A list of search results (structure)
:param search_string: A dict with mode (key) and the search value (value)
:param age: Not used
:param ep_obj: Not used
:returns: A list of search results (structure)
"""
results = []
if not self.login():
return results

# Search Params
search_params = {'cat': '12'} if 'Season' in search_strings else {'cat': '10'}
search_params = {
'cat': 10,
}

# Units
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

for mode in search_strings:
items = []
logger.log(u"Search Mode: {}".format(mode), logger.DEBUG)
logger.log('Search mode: {0}'.format(mode), logger.DEBUG)

for search_string in search_strings[mode]:

if mode != 'RSS':
logger.log(u"Search string: {}".format(search_string.decode("utf-8")),
logger.DEBUG)

search_params['search'] = search_string

search_params['cat'] = '12' if mode == 'Season' else '10'
if mode == 'Season':
search_params['cat'] = 12

data = self.get_url(self.urls['search'], params=search_params, returns='text')
if not data:
logger.log(u"No data returned from provider", logger.DEBUG)
response = self.get_url(self.urls['search'], params=search_params, returns='response')
if not response.text:
logger.log('No data returned from provider', logger.DEBUG)
continue

with BS4Parser(data, 'html.parser') as html:
with BS4Parser(response.text, 'html5lib') as html:
torrent_table = html.find('table', width='750')
torrent_rows = torrent_table('tr') if torrent_table else []

# Continue only if at least one Release is found
if len(torrent_rows) < 2:
logger.log(u"Data returned from provider does not contain any torrents", logger.DEBUG)
logger.log('Data returned from provider does not contain any torrents', logger.DEBUG)
continue

# Skip column headers
for result in torrent_rows[1:]:
freeleech = result.get('bgcolor')
if self.freeleech and not freeleech:
continue

try:
cells = result.find_all('td')
cells = result('td')

title = cells[2].find('a')['title']
download_url = result.find_all('td')[0].find('a')['href']
download_url = cells[0].find('a')['href']
if not all([title, download_url]):
continue

Expand All @@ -138,22 +123,26 @@ def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-man
# Filter unseeded torrent
if seeders < min(self.minseed, 1):
if mode != 'RSS':
logger.log(u"Discarding torrent because it doesn't meet the"
u" minimum seeders: {0}. Seeders: {1})".format
logger.log('Discarding torrent because it doesn\'t meet the'
' minimum seeders: {0}. Seeders: {1})'.format
(title, seeders), logger.DEBUG)
continue

freeleech = bool(result.get('bgcolor'))
if self.freeleech and not freeleech:
continue

torrent_size = '{size} {unit}'.format(size=cells[6].contents[0], unit=cells[6].contents[1].get_text())

size = convert_size(torrent_size, units=units) or -1

item = {'title': title, 'link': download_url, 'size': size, 'seeders': seeders, 'leechers': leechers, 'pubdate': None, 'hash': None}
item = {
'title': title,
'link': download_url,
'size': size,
'seeders': seeders,
'leechers': leechers,
'pubdate': None,
'hash': None
}
if mode != 'RSS':
logger.log(u"Found result: {0} with {1} seeders and {2} leechers".format
logger.log('Found result: {0} with {1} seeders and {2} leechers'.format
(title, seeders, leechers), logger.DEBUG)

items.append(item)
Expand All @@ -166,4 +155,29 @@ def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-man

return results


def login(self):
"""Login method used for logging in before doing search and torrent downloads"""
if any(dict_from_cookiejar(self.session.cookies).values()):
return True

login_params = {
'username': self.username.encode('utf-8'),
'password': self.password.encode('utf-8'),
}

response = self.get_url(self.urls['login'], post_data=login_params, returns='text')
if not response:
logger.log(u'Unable to connect to provider', logger.WARNING)
self.session.cookies.clear()
return False

if '<h2>Login failed!</h2>' in response:
logger.log(u'Invalid username or password. Check your settings', logger.WARNING)
self.session.cookies.clear()
return False

return True


provider = BithdtvProvider()
152 changes: 152 additions & 0 deletions sickbeard/providers/zooqle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# coding=utf-8
# Author: medariox <dariox@gmx.com>
#
# This file is part of Medusa.
#
# Medusa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Medusa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Medusa. If not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

from requests.compat import urljoin

from sickbeard import logger, tvcache
from sickbeard.bs4_parser import BS4Parser

from sickrage.helper.common import convert_size, try_int
from sickrage.providers.torrent.TorrentProvider import TorrentProvider


class ZooqleProvider(TorrentProvider): # pylint: disable=too-many-instance-attributes
"""Zooqle Torrent provider"""
def __init__(self):

# Provider Init
TorrentProvider.__init__(self, 'Zooqle')

# Credentials
self.public = True

# Torrent Stats
self.minseed = None
self.minleech = None

# URLs
self.url = 'https://zooqle.com/'
self.urls = {
'search': urljoin(self.url, '/search'),
}

# Proper Strings
self.proper_strings = ['PROPER', 'REPACK', 'REAL']

# Cache
self.cache = tvcache.TVCache(self, min_time=15)

def search(self, search_strings, age=0, ep_obj=None): # pylint: disable=too-many-locals, too-many-branches
"""
Zooqle search and parsing
:param search_string: A dict with mode (key) and the search value (value)
:param age: Not used
:param ep_obj: Not used
:returns: A list of search results (structure)
"""
results = []

# Search Params
search_params = {
'q': '* category:TV',
's': 'dt',
'v': 't',
'sd': 'd',
}

# Units
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']

for mode in search_strings:
items = []
logger.log('Search mode: {0}'.format(mode), logger.DEBUG)

for search_string in search_strings[mode]:

if mode != 'RSS':
search_params = {'q': '{0}+category:TV'.format(search_strings)}

response = self.get_url(self.urls['search'], params=search_params, returns='response')
if not response.text:
logger.log('No data returned from provider', logger.DEBUG)
continue

with BS4Parser(response.text, 'html5lib') as html:
torrent_table = html.find('div', class_='panel-body')
torrent_rows = torrent_table('tr') if torrent_table else []

# Continue only if at least one Release is found
if len(torrent_rows) < 2:
logger.log('Data returned from provider does not contain any torrents', logger.DEBUG)
continue

# Skip column headers
for result in torrent_rows[1:]:

try:
cells = result('td')

title = cells[1].find('a').get_text()
download_url = cells[2].find('a')['href']
if not all([title, download_url]):
continue

peers = cells[6].find('div')['title'].replace(',', '').split(' | ', 1)
seeders = try_int(peers[0].strip('Seeders: '))
leechers = try_int(peers[1].strip('Leechers: '))

# Filter unseeded torrent
if seeders < min(self.minseed, 1):
if mode != 'RSS':
logger.log('Discarding torrent because it doesn\'t meet the'
' minimum seeders: {0}. Seeders: {1})'.format
(title, seeders), logger.DEBUG)
continue

torrent_size = cells[4].get_text(strip=True)

size = convert_size(torrent_size, units=units) or -1

item = {
'title': title,
'link': download_url,
'size': size,
'seeders': seeders,
'leechers': leechers,
'pubdate': None,
'hash': None
}
if mode != 'RSS':
logger.log('Found result: {0} with {1} seeders and {2} leechers'.format
(title, seeders, leechers), logger.DEBUG)

items.append(item)
except StandardError:
continue

# For each search mode sort all the items by seeders if available
items.sort(key=lambda d: try_int(d.get('seeders', 0)), reverse=True)
results += items

return results


provider = ZooqleProvider()

0 comments on commit 3e0c619

Please sign in to comment.