Refactor again

This commit is contained in:
Michel Roux 2019-11-30 16:52:13 +01:00
parent dbddd8dcc7
commit 79f847316c
4 changed files with 209 additions and 125 deletions

35
app.py
View File

@ -1,8 +1,9 @@
from os import environ from os import environ
from flask import redirect, render_template, url_for from flask import redirect, render_template, url_for, request
from config import app, auth from config import app, auth
from connectors import *
from models import SearchForm from models import SearchForm
@ -15,14 +16,38 @@ def verify_password(username, password):
@app.route('/') @app.route('/')
def home(): def home():
form = SearchForm() return render_template('home.html', form=SearchForm())
if form.validate_on_submit():
return redirect(url_for('search', q=form.q))
return render_template('home.html', form=form)
@app.route('/search') @app.route('/search')
def search(): def search():
query = request.args.get('q')
if not query:
return redirect(url_for('home'))
results = [
Nyaa(query).run(),
Pantsu(query).run(),
YggTorrent(query, category=2179).run(),
YggTorrent(query, category=2178).run(),
AnimeUltime(query).run(),
]
return render_template('search.html', form=SearchForm(), connectors=results)
@app.route('/latest')
def latest():
return 'Hello!'
@app.route('/list')
def list_animes():
return 'Hello!'
@app.route('/admin')
@auth.login_required
def admin():
return 'Hello!' return 'Hello!'

View File

@ -1,36 +1,52 @@
from subprocess import run import locale
from bs4 import BeautifulSoup import re
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime, timedelta from datetime import datetime, timedelta
from enum import Enum
from subprocess import run
from sys import platform from sys import platform
import re
import requests import requests
import locale from bs4 import BeautifulSoup
class ConnectorException(Exception): class ConnectorReturn(Enum):
def __init__(self, connector_type): SEARCH = 1
super().__init__("Error, can't grab data from %s" % connector_type) HISTORY = 2
class Connector(ABC): class Connector(ABC):
blacklist_words = ['Chris44', 'Vol.'] blacklist_words = ['Chris44', 'Vol.']
def __init__(self, query): def __init__(self, query, page=1, return_type=ConnectorReturn.SEARCH, category=None):
self.query = query self.query = query
self.category = category
self.data = []
self.is_more = False
self.on_error = False
self.page = page
self.return_type = return_type
@abstractmethod @abstractmethod
def get_full_search_url(self, sort_type, page, category): def get_full_search_url(self):
pass pass
@abstractmethod @abstractmethod
def search(self, sort_type, page, category): def __search(self):
pass pass
@abstractmethod @abstractmethod
def get_history(self, sort_type, page, category): def __get_history(self):
pass pass
def run(self):
if not len(self.data):
if self.return_type is ConnectorReturn.SEARCH:
self.__search()
elif self.return_type is ConnectorReturn.HISTORY:
self.__get_history()
return self
def curl_content(self, url, params=None, ajax=False): def curl_content(self, url, params=None, ajax=False):
if isinstance(self, YggTorrent): if isinstance(self, YggTorrent):
try: try:
@ -91,19 +107,20 @@ class Nyaa(Connector):
title = 'Nyaa' title = 'Nyaa'
favicon = 'nyaa.png' favicon = 'nyaa.png'
base_url = 'https://nyaa.si' base_url = 'https://nyaa.si'
default_sort = 'size'
def get_full_search_url(self, sort_type=default_sort, page=1, category=None): def get_full_search_url(self):
sort_type = 'size'
if self.return_type is ConnectorReturn.HISTORY:
sort_type = 'date'
to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query) to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query)
return '%s/?f=0&c=1_3&s=%s&o=desc&q=%s&p=%s' % (self.base_url, sort_type, to_query, page) return '%s/?f=0&c=1_3&s=%s&o=desc&q=%s&p=%s' % (self.base_url, sort_type, to_query, self.page)
def get_history(self, sort_type=default_sort, page=1, category=None): def __get_history(self):
output = self.search(sort_type, page, category) self.__search()
return output[0]
def search(self, sort_type=default_sort, page=1, category=None): def __search(self):
data = [] response = self.curl_content(self.get_full_search_url())
response = self.curl_content(self.get_full_search_url(sort_type, page))
if response['http_code'] is 200: if response['http_code'] is 200:
html = BeautifulSoup(response['output'], 'html.parser') html = BeautifulSoup(response['output'], 'html.parser')
@ -133,7 +150,7 @@ class Nyaa(Connector):
valid_trs = valid_trs + 1 valid_trs = valid_trs + 1
data.append({ self.data.append({
'lang': self.get_lang(url.string), 'lang': self.get_lang(url.string),
'href': '%s%s' % (self.base_url, url['href']), 'href': '%s%s' % (self.base_url, url['href']),
'name': self.boldify(url.string), 'name': self.boldify(url.string),
@ -148,9 +165,9 @@ class Nyaa(Connector):
'class': 'is-%s' % tr['class'][0] 'class': 'is-%s' % tr['class'][0]
}) })
return data, valid_trs is not len(trs) self.is_more = valid_trs is not len(trs)
else: else:
raise ConnectorException(self.title) self.on_error = True
class Pantsu(Connector): class Pantsu(Connector):
@ -158,19 +175,20 @@ class Pantsu(Connector):
title = 'Pantsu' title = 'Pantsu'
favicon = 'pantsu.png' favicon = 'pantsu.png'
base_url = 'https://nyaa.net' base_url = 'https://nyaa.net'
default_sort = 4
def get_full_search_url(self, sort_type=default_sort, page=1, category=None): def get_full_search_url(self):
sort_type = 4
if self.return_type is ConnectorReturn.HISTORY:
sort_type = 2
to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query) to_query = '(%s vf)|(%s vostfr)|(%s multi)|(%s french)' % (self.query, self.query, self.query, self.query)
return '%s/search/%s?c=3_13&order=false&q=%s&sort=%s' % (self.base_url, page, to_query, sort_type) return '%s/search/%s?c=3_13&order=false&q=%s&sort=%s' % (self.base_url, self.page, to_query, sort_type)
def get_history(self, sort_type=default_sort, page=1, category=None): def __get_history(self):
output = self.search(sort_type, page, category) self.__search()
return output[0]
def search(self, sort_type=default_sort, page=1, category=None): def __search(self):
data = [] response = self.curl_content(self.get_full_search_url())
response = self.curl_content(self.get_full_search_url(sort_type, page))
if response['http_code'] is 200: if response['http_code'] is 200:
html = BeautifulSoup(response['output'], 'html.parser') html = BeautifulSoup(response['output'], 'html.parser')
@ -193,7 +211,7 @@ class Pantsu(Connector):
valid_trs = valid_trs + 1 valid_trs = valid_trs + 1
data.append({ self.data.append({
'lang': self.get_lang(url.string), 'lang': self.get_lang(url.string),
'href': '%s%s' % (self.base_url, url['href']), 'href': '%s%s' % (self.base_url, url['href']),
'name': self.boldify(url.string), 'name': self.boldify(url.string),
@ -211,9 +229,9 @@ class Pantsu(Connector):
'class': 'is-%s' % tr['class'][0] 'class': 'is-%s' % tr['class'][0]
}) })
return data, valid_trs is not len(trs) self.is_more = valid_trs is not len(trs)
else: else:
raise ConnectorException(self.title) self.on_error = True
class YggTorrent(Connector): class YggTorrent(Connector):
@ -221,70 +239,65 @@ class YggTorrent(Connector):
title = 'YggTorrent' title = 'YggTorrent'
favicon = 'yggtorrent.png' favicon = 'yggtorrent.png'
base_url = 'https://www2.yggtorrent.pe' base_url = 'https://www2.yggtorrent.pe'
default_sort = 'size'
def get_full_search_url(self, sort_type=default_sort, page=1, category=None): def get_full_search_url(self):
if category is None: sort_type = 'size'
raise ConnectorException(self.title) if self.return_type is ConnectorReturn.HISTORY:
sort_type = 'date'
return '%s/engine/search?do=search&order=desc&sort=%s&category=2145&sub_category=%s&name=%s&page=%s' % ( return '%s/engine/search?do=search&order=desc&sort=%s&category=2145&sub_category=%s&name=%s&page=%s' % (
self.base_url, sort_type, category, self.query, page self.base_url, sort_type, self.category, self.query, self.page
) )
def get_history(self, sort_type=default_sort, page=1, category=None): def __get_history(self):
if category is None: self.__search()
raise ConnectorException(self.title)
output = self.search(sort_type, page, category) def __search(self):
return output[0] if self.category is None:
self.on_error = True
else:
response = self.curl_content(self.get_full_search_url())
def search(self, sort_type=default_sort, page=1, category=None): if response['http_code'] is 200:
if category is None: html = BeautifulSoup(response['output'], 'html.parser')
raise ConnectorException(self.title) trs = html.select('table.table tr')
valid_trs = 0
data = [] for i, tr in enumerate(trs):
response = self.curl_content(self.get_full_search_url(sort_type, page, category)) if not i:
if response['http_code'] is 200:
html = BeautifulSoup(response['output'], 'html.parser')
trs = html.select('table.table tr')
valid_trs = 0
for i, tr in enumerate(trs):
if not i:
continue
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
if any(url.string in word for word in self.blacklist_words):
continue continue
valid_trs = valid_trs + 1 tds = tr.findAll('td')
check_downloads = int(tds[6].string)
check_seeds = int(tds[7].string)
data.append({ if check_downloads or check_seeds:
'lang': self.get_lang(url.string), url = tds[1].a
'href': url['href'],
'name': self.boldify(url.string),
'comment': '<a href="%s#comm" target="_blank"><i class="fa fa-comments-o"></i>%s</a>' %
(url['href'], tds[3].string),
'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)),
'size': tds[5].string,
'date': datetime.fromtimestamp(int(tds[4].div.string)).strftime('%Y-%m-%d %H:%M:%S'),
'seeds': check_seeds,
'leechs': tds[8].string,
'downloads': check_downloads,
'class': ''
})
return data, valid_trs is len(trs) if any(url.string in word for word in self.blacklist_words):
else: continue
raise ConnectorException(self.title)
valid_trs = valid_trs + 1
self.data.append({
'lang': self.get_lang(url.string),
'href': url['href'],
'name': self.boldify(url.string),
'comment': '<a href="%s#comm" target="_blank"><i class="fa fa-comments-o"></i>%s</a>' %
(url['href'], tds[3].string),
'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)),
'size': tds[5].string,
'date': datetime.fromtimestamp(int(tds[4].div.string)).strftime('%Y-%m-%d %H:%M:%S'),
'seeds': check_seeds,
'leechs': tds[8].string,
'downloads': check_downloads,
'class': ''
})
self.is_more = valid_trs is not len(trs)
else:
self.on_error = True
class AnimeUltime(Connector): class AnimeUltime(Connector):
@ -292,20 +305,20 @@ class AnimeUltime(Connector):
title = 'Anime-Ultime' title = 'Anime-Ultime'
favicon = 'animeultime.png' favicon = 'animeultime.png'
base_url = 'http://www.anime-ultime.net' base_url = 'http://www.anime-ultime.net'
default_sort = 'search'
def get_full_search_url(self, sort_type=default_sort, page=1, category=None): def get_full_search_url(self):
if sort_type is 'history': from_date = ''
page_date = datetime.now() - timedelta((page - 1) * 365 / 12) sort_type = 'search'
if self.return_type is ConnectorReturn.HISTORY:
page_date = datetime.now() - timedelta((self.page - 1) * 365 / 12)
from_date = page_date.strftime('%m%Y') from_date = page_date.strftime('%m%Y')
else: sort_type = 'history'
from_date = ''
return '%s/%s-0-1/%s' % (self.base_url, sort_type, from_date) return '%s/%s-0-1/%s' % (self.base_url, sort_type, from_date)
def search(self, sort_type=default_sort, page=1, category=None): def __search(self):
data = [] response = self.curl_content(self.get_full_search_url(), {'search': self.query})
response = self.curl_content(self.get_full_search_url(sort_type, page), {'search': self.query})
if response['http_code'] is 200: if response['http_code'] is 200:
html = BeautifulSoup(response['output'], 'html.parser') html = BeautifulSoup(response['output'], 'html.parser')
@ -325,7 +338,7 @@ class AnimeUltime(Connector):
url = tds[0].a url = tds[0].a
data.append({ self.data.append({
'lang': 'jp', 'lang': 'jp',
'href': '%s/%s' % (self.base_url, url['href']), 'href': '%s/%s' % (self.base_url, url['href']),
'name': url.decode_contents(), 'name': url.decode_contents(),
@ -336,20 +349,17 @@ class AnimeUltime(Connector):
name = html.select('h1') name = html.select('h1')
ani_type = html.select('div.titre') ani_type = html.select('div.titre')
data.append({ self.data.append({
'lang': 'jp', 'lang': 'jp',
'href': '%s%s' % (self.get_full_search_url('file'), player[0]['data-serie']), 'href': '%s%s' % (self.get_file_url(), player[0]['data-serie']),
'name': self.boldify(name[0].string), 'name': self.boldify(name[0].string),
'type': ani_type[0].string.replace(':', '') 'type': ani_type[0].string.replace(':', '')
}) })
return data, False
else: else:
raise ConnectorException(self.title) self.on_error = True
def get_history(self, sort_type=default_sort, page=1, category=None): def __get_history(self):
data = [] response = self.curl_content(self.get_full_search_url())
response = self.curl_content(self.get_full_search_url('history', page))
if response['http_code'] is 200: if response['http_code'] is 200:
html = BeautifulSoup(response['output'], 'html.parser') html = BeautifulSoup(response['output'], 'html.parser')
@ -369,7 +379,7 @@ class AnimeUltime(Connector):
release_date = datetime.strptime(h3s[i].string, '%A %d %B %Y : ').strftime('%Y-%m-%d %H:%M:%S') release_date = datetime.strptime(h3s[i].string, '%A %d %B %Y : ').strftime('%Y-%m-%d %H:%M:%S')
locale.setlocale(locale.LC_ALL, current_locale) locale.setlocale(locale.LC_ALL, current_locale)
data.append({ self.data.append({
'lang': 'jp', 'lang': 'jp',
'href': '%s%s' % (self.get_full_search_url('file'), link['href']), 'href': '%s%s' % (self.get_full_search_url('file'), link['href']),
'name': link.string, 'name': link.string,
@ -377,21 +387,17 @@ class AnimeUltime(Connector):
'date': release_date 'date': release_date
}) })
return data
else:
raise ConnectorException(self.title)
class Other(Connector): class Other(Connector):
color = 'is-danger' color = 'is-danger'
title = 'Other' title = 'Other'
favicon = 'blank.png' favicon = 'blank.png'
def get_full_search_url(self, sort_type=None, page=1, category=None): def get_full_search_url(self):
return '' pass
def search(self, sort_type=None, page=1, category=None): def __search(self):
return [], False pass
def get_history(self, sort_type, page, category): def __get_history(self):
return [] pass

View File

@ -16,13 +16,31 @@
<nav class="navbar is-dark" role="navigation" aria-label="main navigation"> <nav class="navbar is-dark" role="navigation" aria-label="main navigation">
<div class="navbar-start"> <div class="navbar-start">
{% block internal_buttons %}{% endblock %} <a class="navbar-item tooltip is-tooltip-bottom" data-tooltip="Latest torrents" href="{{ url_for('latest') }}">
{% block external_buttons %}{% endblock %} <i class="fa fa-newspaper-o"></i><i>&nbsp;</i><span class="is-hidden-mobile">Latest torrents</span>
{% block add_button %}{% endblock %} </a>
<a class="navbar-item tooltip is-tooltip-bottom" data-tooltip="My seeded torrents"
href="{{ url_for('list_animes') }}">
<i class="fa fa-cloud-download"></i><i>&nbsp;</i><span class="is-hidden-mobile">My seeded torrents</span>
</a>
{% if request.args.get('q') %}
<a class="navbar-item tooltip is-tooltip-bottom" data-tooltip="TVDB"
href="https://www.thetvdb.com/search?menu%5Btype%5D=TV&query={{ request.args.get('q') }}"
target="_blank">
<i class="fa fa-television"></i><i>&nbsp;</i><span class="is-hidden-mobile">TVDB</span>
</a>
<a class="navbar-item tooltip is-tooltip-bottom" data-tooltip="Nautiljon"
href="https://www.nautiljon.com/search.php?q={{ request.args.get('q') }}" target="_blank">
<i class="fa fa-rss"></i><i>&nbsp;</i><span class="is-hidden-mobile">Nautiljon</span>
</a>
<a class="navbar-item tooltip is-tooltip-bottom" data-tooltip="Animes-Mangas-DDL"
href="https://animemangaddl.com/?s={{ request.args.get('q') }}" target="_blank">
<i class="fa fa-adn"></i><i>&nbsp;</i><span class="is-hidden-mobile">A-M-DDL</span>
</a>
{% endif %}
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<form action="{{ url_for('search') }}" class="navbar-item"> <form action="{{ url_for('search') }}" class="navbar-item">
{{ form.csrf_token }}
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
{{ form.q(placeholder='Search ...', class='input') }} {{ form.q(placeholder='Search ...', class='input') }}

35
templates/search.html Normal file
View File

@ -0,0 +1,35 @@
{% extends "layout.html" %}
{% block title %}Animes torrents search engine - {{ request.args.get('q') }}{% endblock %}
{% block body %}
<table class="table is-bordered is-striped is-narrow is-fullwidth is-hoverable search">
<thead>
<tr>
<th>Name</th>
<th>
<i class="fa fa-comment"></i>
</th>
<th>Link</th>
<th>Size</th>
<th>Date</th>
<th>
<i class="fa fa-arrow-up"></i>
</th>
<th>
<i class="fa fa-arrow-down"></i>
</th>
<th>
<i class="fa fa fa-check"></i>
</th>
</tr>
</thead>
<tbody>
{% for connector in connectors %}
{% for torrent in connector.data %}
{% enfor %}
{% endfor %}
</tbody>
</table>
{% endblock %}