@@ -0,0 +1,115 @@
1+"""
2+ Nyaa.se (Anime Bittorrent tracker)
3+
4+ @website http://www.nyaa.se/
5+ @provide-api no
6+ @using-api no
7+ @results HTML
8+ @stable no (HTML can change)
9+ @parse url, title, content, seed, leech, torrentfile
10+"""
11+
12+from cgi import escape
13+from urllib import urlencode
14+from lxml import html
15+from searx.engines.xpath import extract_text
16+
17+# engine dependent config
18+categories = ['files', 'images', 'videos', 'music']
19+paging = True
20+
21+# search-url
22+base_url = 'http://www.nyaa.se/'
23+search_url = base_url + '?page=search&{query}&offset={offset}'
24+
25+# xpath queries
26+xpath_results = '//table[@class="tlist"]//tr[contains(@class, "tlistrow")]'
27+xpath_category = './/td[@class="tlisticon"]/a'
28+xpath_title = './/td[@class="tlistname"]/a'
29+xpath_torrent_file = './/td[@class="tlistdownload"]/a'
30+xpath_filesize = './/td[@class="tlistsize"]/text()'
31+xpath_seeds = './/td[@class="tlistsn"]/text()'
32+xpath_leeches = './/td[@class="tlistln"]/text()'
33+xpath_downloads = './/td[@class="tlistdn"]/text()'
34+
35+
36+# convert a variable to integer or return 0 if it's not a number
37+def int_or_zero(num):
38+ if isinstance(num, list):
39+ if len(num) < 1:
40+ return 0
41+ num = num[0]
42+ if num.isdigit():
43+ return int(num)
44+ return 0
45+
46+
47+# do search-request
48+def request(query, params):
49+ query = urlencode({'term': query})
50+ params['url'] = search_url.format(query=query, offset=params['pageno'])
51+ return params
52+
53+
54+# get response from search-request
55+def response(resp):
56+ results = []
57+
58+ dom = html.fromstring(resp.text)
59+
60+ for result in dom.xpath(xpath_results):
61+ # category in which our torrent belongs
62+ category = result.xpath(xpath_category)[0].attrib.get('title')
63+
64+ # torrent title
65+ page_a = result.xpath(xpath_title)[0]
66+ title = escape(extract_text(page_a))
67+
68+ # link to the page
69+ href = page_a.attrib.get('href')
70+
71+ # link to the torrent file
72+ torrent_link = result.xpath(xpath_torrent_file)[0].attrib.get('href')
73+
74+ # torrent size
75+ try:
76+ file_size, suffix = result.xpath(xpath_filesize)[0].split(' ')
77+
78+ # convert torrent size to bytes.
79+ # if there is no correct index in this dictionary,
80+ # the try block fails as it should
81+ multiplier = {
82+ 'KIB': 1024,
83+ 'MIB': 1024 ** 2,
84+ 'GIB': 1024 ** 3,
85+ 'TIB': 1024 ** 4
86+ }[suffix.upper()]
87+
88+ file_size = int(float(file_size) * multiplier)
89+ except Exception as e:
90+ file_size = None
91+
92+ # seed count
93+ seed = int_or_zero(result.xpath(xpath_seeds))
94+
95+ # leech count
96+ leech = int_or_zero(result.xpath(xpath_leeches))
97+
98+ # torrent downloads count
99+ downloads = int_or_zero(result.xpath(xpath_downloads))
100+
101+ # content string contains all information not included into template
102+ content = 'Category: "{category}". Downloaded {downloads} times.'
103+ content = content.format(category=category, downloads=downloads)
104+ content = escape(content)
105+
106+ results.append({'url': href,
107+ 'title': title,
108+ 'content': content,
109+ 'seed': seed,
110+ 'leech': leech,
111+ 'filesize': file_size,
112+ 'torrentfile': torrent_link,
113+ 'template': 'torrent.html'})
114+
115+ return results