2019-11-30 15:52:13 +00:00
|
|
|
import locale
|
|
|
|
import re
|
2019-11-25 21:52:22 +00:00
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
from datetime import datetime, timedelta
|
2019-11-30 15:52:13 +00:00
|
|
|
from enum import Enum
|
2019-12-04 18:58:35 +00:00
|
|
|
from functools import wraps
|
2020-03-22 19:01:18 +00:00
|
|
|
from logging import getLogger
|
2019-12-15 18:48:34 +00:00
|
|
|
from urllib.parse import quote
|
2019-11-30 15:52:13 +00:00
|
|
|
|
|
|
|
from bs4 import BeautifulSoup
|
2020-04-06 13:46:45 +00:00
|
|
|
from cloudscraper import create_scraper
|
2020-04-06 14:51:48 +00:00
|
|
|
from requests import RequestException
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-02-21 16:11:07 +00:00
|
|
|
from config import IS_DEBUG, CACHE_TIMEOUT, BLACKLIST_WORDS
|
2019-12-11 18:17:36 +00:00
|
|
|
from models import AnimeLink
|
2019-11-30 22:42:35 +00:00
|
|
|
|
2020-04-06 13:46:45 +00:00
|
|
|
scraper = create_scraper()
|
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
class ConnectorReturn(Enum):
|
|
|
|
SEARCH = 1
|
|
|
|
HISTORY = 2
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
|
2019-11-30 22:42:35 +00:00
|
|
|
class ConnectorLang(Enum):
|
|
|
|
FR = '🇫🇷'
|
|
|
|
JP = '🇯🇵'
|
|
|
|
|
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
class Cache:
|
|
|
|
CACHE_DATA = {}
|
|
|
|
|
|
|
|
def cache_data(self, f):
|
|
|
|
@wraps(f)
|
|
|
|
def wrapper(*args, **kwds):
|
|
|
|
connector = args[0]
|
|
|
|
timestamp = datetime.now().timestamp()
|
|
|
|
|
2020-01-05 10:01:32 +00:00
|
|
|
# clear old data
|
2020-01-05 10:17:58 +00:00
|
|
|
for connector_class in list(self.CACHE_DATA):
|
|
|
|
for connector_func in list(self.CACHE_DATA[connector_class]):
|
|
|
|
for connector_query in list(self.CACHE_DATA[connector_class][connector_func]):
|
|
|
|
for connector_page in list(self.CACHE_DATA[connector_class][connector_func][connector_query]):
|
2020-01-05 10:19:39 +00:00
|
|
|
if self.CACHE_DATA[connector_class][connector_func][connector_query][connector_page][
|
|
|
|
'timeout'
|
|
|
|
] < timestamp:
|
2020-01-05 10:17:58 +00:00
|
|
|
del self.CACHE_DATA[connector_class][connector_func][connector_query][connector_page]
|
2020-01-05 10:01:32 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if connector.__class__.__name__ not in self.CACHE_DATA:
|
|
|
|
self.CACHE_DATA[connector.__class__.__name__] = {}
|
|
|
|
if f.__name__ not in self.CACHE_DATA[connector.__class__.__name__]:
|
|
|
|
self.CACHE_DATA[connector.__class__.__name__][f.__name__] = {}
|
|
|
|
if connector.query not in self.CACHE_DATA[connector.__class__.__name__][f.__name__]:
|
|
|
|
self.CACHE_DATA[connector.__class__.__name__][f.__name__][connector.query] = {}
|
|
|
|
if connector.page not in self.CACHE_DATA[connector.__class__.__name__][f.__name__][connector.query]:
|
|
|
|
self.CACHE_DATA[connector.__class__.__name__][f.__name__][connector.query][connector.page] = {
|
2019-12-07 17:31:10 +00:00
|
|
|
'timeout': 0.0
|
2019-12-04 18:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cached_data = self.CACHE_DATA[connector.__class__.__name__][f.__name__][connector.query][connector.page]
|
|
|
|
if cached_data['timeout'] > timestamp:
|
|
|
|
connector.data = cached_data['data']
|
2019-12-05 17:53:23 +00:00
|
|
|
connector.is_more = cached_data['is_more']
|
2019-12-13 19:10:04 +00:00
|
|
|
connector.on_error = False
|
2019-12-04 18:58:35 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
ret = f(*args, **kwds)
|
2019-12-05 17:53:23 +00:00
|
|
|
if not connector.on_error:
|
|
|
|
self.CACHE_DATA[connector.__class__.__name__][f.__name__][connector.query][connector.page] = {
|
|
|
|
'data': connector.data,
|
2019-12-23 09:34:38 +00:00
|
|
|
'timeout': timestamp + CACHE_TIMEOUT,
|
2019-12-05 17:53:23 +00:00
|
|
|
'is_more': connector.is_more
|
|
|
|
}
|
2019-12-04 18:58:35 +00:00
|
|
|
return ret
|
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
ConnectorCache = Cache()
|
|
|
|
|
|
|
|
|
2020-04-06 14:51:48 +00:00
|
|
|
def curl_content(url, params=None, ajax=False):
|
|
|
|
if ajax:
|
|
|
|
headers = {'X-Requested-With': 'XMLHttpRequest'}
|
|
|
|
else:
|
|
|
|
headers = {}
|
|
|
|
|
|
|
|
try:
|
|
|
|
if params is not None:
|
|
|
|
response = scraper.post(url, params, timeout=5, headers=headers)
|
|
|
|
else:
|
|
|
|
response = scraper.get(url, timeout=5, headers=headers)
|
|
|
|
|
|
|
|
output = response.text
|
|
|
|
http_code = response.status_code
|
|
|
|
except RequestException as e:
|
|
|
|
output = ''
|
|
|
|
http_code = 500
|
|
|
|
if IS_DEBUG:
|
|
|
|
getLogger().exception(e)
|
|
|
|
|
|
|
|
return {'http_code': http_code, 'output': output}
|
|
|
|
|
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
class Connector(ABC):
|
2019-12-01 17:30:24 +00:00
|
|
|
@property
|
|
|
|
@abstractmethod
|
|
|
|
def color(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@property
|
|
|
|
@abstractmethod
|
|
|
|
def title(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@property
|
|
|
|
@abstractmethod
|
|
|
|
def favicon(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@property
|
|
|
|
@abstractmethod
|
|
|
|
def base_url(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@property
|
|
|
|
@abstractmethod
|
|
|
|
def is_light(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __init__(self, query, page=1, return_type=ConnectorReturn.SEARCH):
|
2019-11-25 21:52:22 +00:00
|
|
|
self.query = query
|
2019-11-30 15:52:13 +00:00
|
|
|
self.data = []
|
|
|
|
self.is_more = False
|
2019-11-30 17:09:30 +00:00
|
|
|
self.on_error = True
|
2019-11-30 15:52:13 +00:00
|
|
|
self.page = page
|
|
|
|
self.return_type = return_type
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
@abstractmethod
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
2019-11-25 21:52:22 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
@abstractmethod
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2019-11-25 21:52:22 +00:00
|
|
|
pass
|
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@abstractmethod
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
2019-11-25 21:52:22 +00:00
|
|
|
pass
|
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def run(self):
|
2019-11-30 17:09:30 +00:00
|
|
|
if self.on_error:
|
2019-11-30 15:52:13 +00:00
|
|
|
if self.return_type is ConnectorReturn.SEARCH:
|
2019-11-30 17:09:30 +00:00
|
|
|
self.search()
|
2019-11-30 15:52:13 +00:00
|
|
|
elif self.return_type is ConnectorReturn.HISTORY:
|
2019-11-30 17:09:30 +00:00
|
|
|
self.get_history()
|
2019-11-30 15:52:13 +00:00
|
|
|
return self
|
|
|
|
|
2019-11-28 15:07:26 +00:00
|
|
|
@staticmethod
|
|
|
|
def get_instance(url, query):
|
2019-11-25 21:52:22 +00:00
|
|
|
if 'nyaa.si' in url:
|
2019-11-28 15:07:26 +00:00
|
|
|
return Nyaa(query)
|
2019-11-25 21:52:22 +00:00
|
|
|
elif 'nyaa.net' in url:
|
2019-11-28 15:07:26 +00:00
|
|
|
return Pantsu(query)
|
2019-11-25 21:52:22 +00:00
|
|
|
elif 'anime-ultime' in url:
|
2019-11-28 15:07:26 +00:00
|
|
|
return AnimeUltime(query)
|
2019-11-25 21:52:22 +00:00
|
|
|
elif 'ygg' in url:
|
2019-11-28 15:07:26 +00:00
|
|
|
return YggTorrent(query)
|
2019-11-25 21:52:22 +00:00
|
|
|
else:
|
2019-11-28 15:07:26 +00:00
|
|
|
return Other(query)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-28 15:07:26 +00:00
|
|
|
@staticmethod
|
|
|
|
def get_lang(str_to_test):
|
2019-11-25 21:52:22 +00:00
|
|
|
if re.search('(vf|multi|french)', str_to_test, re.IGNORECASE):
|
2019-11-30 22:42:35 +00:00
|
|
|
return ConnectorLang.FR
|
2019-11-25 21:52:22 +00:00
|
|
|
else:
|
2019-11-30 22:42:35 +00:00
|
|
|
return ConnectorLang.JP
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-02 20:50:00 +00:00
|
|
|
@staticmethod
|
|
|
|
def boldify(str_to_replace, keyword):
|
|
|
|
if keyword:
|
|
|
|
return re.sub('(%s)' % keyword, r'<b>\1</b>', str_to_replace, flags=re.IGNORECASE)
|
2019-11-25 21:52:22 +00:00
|
|
|
else:
|
|
|
|
return str_to_replace
|
|
|
|
|
|
|
|
|
|
|
|
class Nyaa(Connector):
|
|
|
|
color = 'is-link'
|
|
|
|
title = 'Nyaa'
|
|
|
|
favicon = 'nyaa.png'
|
|
|
|
base_url = 'https://nyaa.si'
|
2019-11-30 22:42:35 +00:00
|
|
|
is_light = False
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
|
|
|
sort_type = 'size'
|
|
|
|
if self.return_type is ConnectorReturn.HISTORY:
|
2019-12-03 21:43:53 +00:00
|
|
|
sort_type = 'id'
|
2019-11-30 15:52:13 +00:00
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query)
|
2019-11-30 15:52:13 +00:00
|
|
|
return '%s/?f=0&c=1_3&s=%s&o=desc&q=%s&p=%s' % (self.base_url, sort_type, to_query, self.page)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
|
|
|
self.search()
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@ConnectorCache.cache_data
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2020-04-06 14:51:48 +00:00
|
|
|
response = curl_content(self.get_full_search_url())
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-09 09:31:35 +00:00
|
|
|
if response['http_code'] == 200:
|
2019-12-04 18:58:35 +00:00
|
|
|
html = BeautifulSoup(response['output'], 'html.parser')
|
|
|
|
trs = html.select('table.torrent-list tr')
|
|
|
|
valid_trs = 0
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
for i, tr in enumerate(trs):
|
|
|
|
if not i:
|
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
tds = tr.findAll('td')
|
|
|
|
check_downloads = int(tds[7].string)
|
|
|
|
check_seeds = int(tds[5].string)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if check_downloads or check_seeds:
|
|
|
|
urls = tds[1].findAll('a')
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if len(urls) > 1:
|
|
|
|
url = urls[1]
|
|
|
|
has_comment = True
|
|
|
|
else:
|
|
|
|
url = urls[0]
|
|
|
|
has_comment = False
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-07 08:51:00 +00:00
|
|
|
url_safe = url.get_text()
|
|
|
|
|
|
|
|
if any(word.lower() in url_safe.lower() for word in BLACKLIST_WORDS):
|
2019-12-04 18:58:35 +00:00
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
valid_trs = valid_trs + 1
|
|
|
|
href = '%s%s' % (self.base_url, url['href'])
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.data.append({
|
2020-04-07 08:51:00 +00:00
|
|
|
'lang': self.get_lang(url_safe),
|
2019-12-04 18:58:35 +00:00
|
|
|
'href': href,
|
2020-04-07 08:51:00 +00:00
|
|
|
'name': url_safe,
|
2019-12-04 18:58:35 +00:00
|
|
|
'comment': str(urls[0]).replace('/view/',
|
|
|
|
'%s%s' % (self.base_url, '/view/')) if has_comment else '',
|
|
|
|
'link': tds[2].decode_contents().replace('/download/',
|
|
|
|
'%s%s' % (self.base_url, '/download/')),
|
|
|
|
'size': tds[3].string,
|
|
|
|
'date': datetime.strptime(tds[4].string, '%Y-%m-%d %H:%M'),
|
|
|
|
'seeds': check_seeds,
|
|
|
|
'leechs': tds[6].string,
|
|
|
|
'downloads': check_downloads,
|
|
|
|
'class': self.color if AnimeLink.query.filter_by(link=href).first() else 'is-%s' %
|
|
|
|
tr['class'][0]
|
|
|
|
})
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.on_error = False
|
2019-12-24 18:38:01 +00:00
|
|
|
self.is_more = valid_trs and valid_trs is not len(trs) - 1
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Pantsu(Connector):
|
|
|
|
color = 'is-info'
|
|
|
|
title = 'Pantsu'
|
|
|
|
favicon = 'pantsu.png'
|
|
|
|
base_url = 'https://nyaa.net'
|
2019-11-30 22:42:35 +00:00
|
|
|
is_light = False
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
|
|
|
sort_type = 4
|
|
|
|
if self.return_type is ConnectorReturn.HISTORY:
|
|
|
|
sort_type = 2
|
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query)
|
2019-11-30 15:52:13 +00:00
|
|
|
return '%s/search/%s?c=3_13&order=false&q=%s&sort=%s' % (self.base_url, self.page, to_query, sort_type)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
|
|
|
self.search()
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@ConnectorCache.cache_data
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2020-04-06 14:51:48 +00:00
|
|
|
response = curl_content(self.get_full_search_url())
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-09 09:31:35 +00:00
|
|
|
if response['http_code'] == 200:
|
2019-12-04 18:58:35 +00:00
|
|
|
html = BeautifulSoup(response['output'], 'html.parser')
|
|
|
|
trs = html.select('div.results tr')
|
|
|
|
valid_trs = 0
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
for i, tr in enumerate(trs):
|
|
|
|
if not i:
|
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
tds = tr.findAll('td')
|
|
|
|
check_downloads = int(tds[6].string.replace('-', '0'))
|
|
|
|
check_seeds = int(tds[4].string.replace('-', '0'))
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if check_downloads or check_seeds:
|
|
|
|
url = tds[1].a
|
2020-04-07 08:51:00 +00:00
|
|
|
url_safe = url.get_text()
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-02-21 16:12:45 +00:00
|
|
|
if any(word.lower() in url_safe.lower() for word in BLACKLIST_WORDS):
|
2019-12-04 18:58:35 +00:00
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
valid_trs = valid_trs + 1
|
|
|
|
href = '%s%s' % (self.base_url, url['href'])
|
|
|
|
splitted_date = re.search(r'(\d+)/(\d+)/(\d+), (\d+):(\d+):(\d+)\s(\w+)\s.+', tds[7]['title'])
|
|
|
|
|
|
|
|
current_locale = locale.getlocale()
|
|
|
|
locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8'))
|
|
|
|
formatted_date = datetime.strptime(
|
|
|
|
'%s/%s/%s, %s:%s:%s %s' % (
|
2020-03-22 15:57:19 +00:00
|
|
|
splitted_date.group(1),
|
|
|
|
splitted_date.group(2),
|
|
|
|
splitted_date.group(3),
|
|
|
|
splitted_date.group(4).zfill(2).replace('00', '12'),
|
|
|
|
splitted_date.group(5),
|
|
|
|
splitted_date.group(6),
|
|
|
|
splitted_date.group(7)
|
2019-12-04 18:58:35 +00:00
|
|
|
), '%m/%d/%Y, %I:%M:%S %p'
|
|
|
|
)
|
|
|
|
locale.setlocale(locale.LC_ALL, current_locale)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.data.append({
|
2019-12-27 14:30:30 +00:00
|
|
|
'lang': self.get_lang(url_safe),
|
2019-12-04 18:58:35 +00:00
|
|
|
'href': href,
|
2019-12-27 14:30:30 +00:00
|
|
|
'name': url_safe,
|
2019-12-04 18:58:35 +00:00
|
|
|
'comment': '',
|
2020-04-06 14:51:48 +00:00
|
|
|
'link': tds[2].decode_contents().replace('icon-magnet', 'fa fa-fw fa-magnet').replace(
|
|
|
|
'icon-floppy', 'fa fa-fw fa-download'),
|
2019-12-04 18:58:35 +00:00
|
|
|
'size': tds[3].string,
|
|
|
|
'date': formatted_date,
|
|
|
|
'seeds': check_seeds,
|
|
|
|
'leechs': tds[5].string,
|
|
|
|
'downloads': check_downloads,
|
2019-12-15 18:52:08 +00:00
|
|
|
'class': self.color if AnimeLink.query.filter_by(link=href).first() else 'is-%s' %
|
|
|
|
tr['class'][0]
|
2019-12-04 18:58:35 +00:00
|
|
|
})
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.on_error = False
|
2019-12-24 18:38:01 +00:00
|
|
|
self.is_more = valid_trs and valid_trs is not len(trs) - 1
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
class YggTorrent(Connector):
|
|
|
|
color = 'is-success'
|
|
|
|
title = 'YggTorrent'
|
|
|
|
favicon = 'yggtorrent.png'
|
2020-02-05 08:38:57 +00:00
|
|
|
base_url = 'https://www2.yggtorrent.se'
|
2019-11-30 22:42:35 +00:00
|
|
|
is_light = False
|
2019-12-01 17:30:24 +00:00
|
|
|
category = 2179
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
|
|
|
sort_type = 'size'
|
|
|
|
if self.return_type is ConnectorReturn.HISTORY:
|
2019-12-03 21:43:53 +00:00
|
|
|
sort_type = 'publish_date'
|
2020-01-29 19:35:42 +00:00
|
|
|
sort_page = '&page=%s' % (self.page * 50) if self.page > 1 else ''
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-15 20:02:27 +00:00
|
|
|
return '%s/engine/search?name=%s&category=2145&sub_category=%s&do=search&order=desc&sort=%s%s' % (
|
|
|
|
self.base_url, self.query, self.category, sort_type, sort_page
|
2019-11-28 17:06:28 +00:00
|
|
|
)
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
|
|
|
self.search()
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@ConnectorCache.cache_data
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2019-12-04 18:58:35 +00:00
|
|
|
if self.category:
|
2020-04-06 14:51:48 +00:00
|
|
|
response = curl_content(self.get_full_search_url())
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-09 09:31:35 +00:00
|
|
|
if response['http_code'] == 200:
|
2019-11-30 15:52:13 +00:00
|
|
|
html = BeautifulSoup(response['output'], 'html.parser')
|
|
|
|
trs = html.select('table.table tr')
|
|
|
|
valid_trs = 0
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
for i, tr in enumerate(trs):
|
|
|
|
if not i:
|
2019-11-25 21:52:22 +00:00
|
|
|
continue
|
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
tds = tr.findAll('td')
|
|
|
|
check_downloads = int(tds[6].string)
|
|
|
|
check_seeds = int(tds[7].string)
|
|
|
|
|
|
|
|
if check_downloads or check_seeds:
|
|
|
|
url = tds[1].a
|
2020-04-07 08:51:00 +00:00
|
|
|
url_safe = url.get_text()
|
2019-11-30 15:52:13 +00:00
|
|
|
|
2020-04-07 08:51:00 +00:00
|
|
|
if any(word.lower() in url_safe.lower() for word in BLACKLIST_WORDS):
|
2019-11-30 15:52:13 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
valid_trs = valid_trs + 1
|
|
|
|
|
|
|
|
self.data.append({
|
2020-04-07 08:51:00 +00:00
|
|
|
'lang': self.get_lang(url_safe),
|
2019-11-30 15:52:13 +00:00
|
|
|
'href': url['href'],
|
2020-04-07 08:51:00 +00:00
|
|
|
'name': url_safe,
|
2019-11-30 15:52:13 +00:00
|
|
|
'comment': '<a href="%s#comm" target="_blank"><i class="fa fa-comments-o"></i>%s</a>' %
|
2019-12-14 10:58:46 +00:00
|
|
|
(url['href'], tds[3].decode_contents()),
|
2019-11-30 17:09:30 +00:00
|
|
|
'link': '<a href="%s/engine/download_torrent?id=%s">'
|
|
|
|
'<i class="fa fa-fw fa-download"></i>'
|
|
|
|
'</a>' % (self.base_url, re.search(r'/(\d+)', url['href']).group(1)),
|
2019-11-30 15:52:13 +00:00
|
|
|
'size': tds[5].string,
|
2019-12-02 20:50:00 +00:00
|
|
|
'date': datetime.fromtimestamp(int(tds[4].div.string)),
|
2019-11-30 15:52:13 +00:00
|
|
|
'seeds': check_seeds,
|
|
|
|
'leechs': tds[8].string,
|
|
|
|
'downloads': check_downloads,
|
2019-12-15 19:00:17 +00:00
|
|
|
'class': self.color if AnimeLink.query.filter_by(
|
|
|
|
link=quote(url['href'], '/+:')
|
|
|
|
).first() else ''
|
2019-11-30 15:52:13 +00:00
|
|
|
})
|
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
self.on_error = False
|
2019-12-24 18:38:01 +00:00
|
|
|
self.is_more = valid_trs and valid_trs is not len(trs) - 1
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
|
2019-12-01 17:30:24 +00:00
|
|
|
class YggAnimation(YggTorrent):
|
|
|
|
title = 'YggAnimation'
|
|
|
|
category = 2178
|
|
|
|
|
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
class AnimeUltime(Connector):
|
|
|
|
color = 'is-warning'
|
|
|
|
title = 'Anime-Ultime'
|
|
|
|
favicon = 'animeultime.png'
|
|
|
|
base_url = 'http://www.anime-ultime.net'
|
2019-11-30 22:42:35 +00:00
|
|
|
is_light = True
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
|
|
|
from_date = ''
|
|
|
|
sort_type = 'search'
|
|
|
|
|
|
|
|
if self.return_type is ConnectorReturn.HISTORY:
|
2019-12-27 13:53:21 +00:00
|
|
|
try:
|
|
|
|
page_date = datetime.now() - timedelta((int(self.page) - 1) * 365 / 12)
|
|
|
|
except OverflowError:
|
|
|
|
page_date = datetime.fromtimestamp(0)
|
2019-11-25 21:52:22 +00:00
|
|
|
from_date = page_date.strftime('%m%Y')
|
2019-11-30 15:52:13 +00:00
|
|
|
sort_type = 'history'
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
return '%s/%s-0-1/%s' % (self.base_url, sort_type, from_date)
|
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@ConnectorCache.cache_data
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2020-04-06 14:51:48 +00:00
|
|
|
response = curl_content(self.get_full_search_url(), {'search': self.query})
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-09 09:31:35 +00:00
|
|
|
if response['http_code'] == 200:
|
2019-12-04 18:58:35 +00:00
|
|
|
html = BeautifulSoup(response['output'], 'html.parser')
|
|
|
|
title = html.select('div.title')
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if 'Recherche' in title[0].string:
|
|
|
|
trs = html.select('table.jtable tr')
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
for i, tr in enumerate(trs):
|
|
|
|
if not i:
|
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
tds = tr.findAll('td')
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
if len(tds) < 2:
|
|
|
|
continue
|
2019-11-30 17:09:30 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
url = tds[0].a
|
|
|
|
href = '%s/%s' % (self.base_url, url['href'])
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
self.data.append({
|
2019-11-30 22:42:35 +00:00
|
|
|
'lang': ConnectorLang.JP,
|
2019-12-04 18:58:35 +00:00
|
|
|
'href': '%s/%s' % (self.base_url, url['href']),
|
2019-12-05 17:53:23 +00:00
|
|
|
'name': url.get_text(),
|
2019-12-04 18:58:35 +00:00
|
|
|
'type': tds[1].string,
|
2020-01-05 10:01:32 +00:00
|
|
|
'date': datetime.fromtimestamp(0),
|
2019-11-30 22:42:35 +00:00
|
|
|
'class': self.color if AnimeLink.query.filter_by(link=href).first() else ''
|
2019-11-25 21:52:22 +00:00
|
|
|
})
|
2019-12-04 18:58:35 +00:00
|
|
|
else:
|
|
|
|
player = html.select('div.AUVideoPlayer')
|
|
|
|
name = html.select('h1')
|
|
|
|
ani_type = html.select('div.titre')
|
|
|
|
href = '%s/file-0-1/%s' % (self.base_url, player[0]['data-serie'])
|
|
|
|
|
|
|
|
self.data.append({
|
|
|
|
'lang': ConnectorLang.JP,
|
|
|
|
'href': '%s/file-0-1/%s' % (self.base_url, player[0]['data-serie']),
|
2019-12-05 17:53:23 +00:00
|
|
|
'name': name[0].string,
|
2019-12-04 18:58:35 +00:00
|
|
|
'type': ani_type[0].string.replace(':', ''),
|
2020-01-05 10:01:32 +00:00
|
|
|
'date': datetime.fromtimestamp(0),
|
2019-12-04 18:58:35 +00:00
|
|
|
'class': self.color if AnimeLink.query.filter_by(link=href).first() else ''
|
|
|
|
})
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
self.on_error = False
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
@ConnectorCache.cache_data
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
2020-04-06 14:51:48 +00:00
|
|
|
response = curl_content(self.get_full_search_url())
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2020-04-09 09:31:35 +00:00
|
|
|
if response['http_code'] == 200:
|
2019-12-04 18:58:35 +00:00
|
|
|
html = BeautifulSoup(response['output'], 'html.parser')
|
|
|
|
tables = html.select('table.jtable')
|
|
|
|
h3s = html.findAll('h3')
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
for i, table in enumerate(tables):
|
|
|
|
for j, tr in enumerate(table.findAll('tr')):
|
|
|
|
if not j:
|
|
|
|
continue
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
tds = tr.findAll('td')
|
|
|
|
link = tds[0].a
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
current_locale = locale.getlocale()
|
|
|
|
locale.setlocale(locale.LC_ALL, ('fr_FR', 'UTF-8'))
|
|
|
|
release_date = datetime.strptime(h3s[i].string, '%A %d %B %Y : ')
|
|
|
|
locale.setlocale(locale.LC_ALL, current_locale)
|
|
|
|
href = '%s/%s' % (self.base_url, link['href'])
|
2019-11-30 17:09:30 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.data.append({
|
|
|
|
'lang': ConnectorLang.JP,
|
|
|
|
'href': '%s/%s' % (self.base_url, link['href']),
|
|
|
|
'name': link.string,
|
|
|
|
'type': tds[4].string,
|
|
|
|
'date': release_date,
|
|
|
|
'class': self.color if AnimeLink.query.filter_by(link=href).first() else ''
|
|
|
|
})
|
2019-11-30 17:09:30 +00:00
|
|
|
|
2019-12-04 18:58:35 +00:00
|
|
|
self.on_error = False
|
2019-11-28 15:07:26 +00:00
|
|
|
|
2019-11-25 21:52:22 +00:00
|
|
|
|
|
|
|
class Other(Connector):
|
|
|
|
color = 'is-danger'
|
|
|
|
title = 'Other'
|
|
|
|
favicon = 'blank.png'
|
2019-12-02 20:50:00 +00:00
|
|
|
base_url = ''
|
2019-11-30 22:42:35 +00:00
|
|
|
is_light = True
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 15:52:13 +00:00
|
|
|
def get_full_search_url(self):
|
|
|
|
pass
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
def search(self):
|
2019-11-30 15:52:13 +00:00
|
|
|
pass
|
2019-11-25 21:52:22 +00:00
|
|
|
|
2019-11-30 17:09:30 +00:00
|
|
|
def get_history(self):
|
2019-11-30 15:52:13 +00:00
|
|
|
pass
|