5
from plugin_urlrewriting import UrlRewritingError
6
from flexget.entry import Entry
7
from flexget.plugin import register_plugin, PluginWarning, internet
8
from flexget.utils.soup import get_soup
9
from flexget.utils.tools import urlopener
10
from flexget.utils.search import StringComparator, torrent_availability
14
socket.setdefaulttimeout(timeout)
16
log = logging.getLogger('newtorrents')
20
"""NewTorrents urlrewriter and search plugin."""
25
# UrlRewriter plugin API
26
def url_rewritable(self, feed, entry):
27
# Return true only for urls that can and should be resolved
28
if entry['url'].startswith('http://www.newtorrents.info/down.php?'):
30
return entry['url'].startswith('http://www.newtorrents.info') and not entry['url'] in self.resolved
32
# UrlRewriter plugin API
33
def url_rewrite(self, feed, entry):
35
if (url.startswith('http://www.newtorrents.info/?q=') or
36
url.startswith('http://www.newtorrents.info/search')):
38
url = self.entries_from_search(entry['title'], url=url)[0]['url']
39
except PluginWarning, e:
40
raise UrlRewritingError(e.value)
42
url = self.url_from_page(url)
46
self.resolved.append(url)
48
raise UrlRewritingError('Bug in newtorrents urlrewriter')
51
def search(self, query, comparator, config=None):
52
return self.entries_from_search(query, comparator=comparator)
55
def url_from_page(self, url):
56
"""Parses torrent url from newtorrents download page"""
58
page = urlopener(url, log)
60
except urllib2.URLError:
61
raise UrlRewritingError('URLerror when retrieving page')
62
p = re.compile("copy\(\'(.*)\'\)", re.IGNORECASE)
65
# the link in which plugin relies is missing!
66
raise UrlRewritingError('Failed to get url from download page. Plugin may need a update.')
71
def entries_from_search(self, name, url=None, comparator=StringComparator(cutoff=0.9)):
72
"""Parses torrent download url from search results"""
73
comparator.set_seq1(name)
74
name = comparator.search_string()
76
url = 'http://www.newtorrents.info/search/%s' % urllib.quote(name, safe=':/~?=&%')
78
log.debug('search url: %s' % url)
80
html = urlopener(url, log).read()
81
# fix </SCR'+'IPT> so that BS does not crash
82
# TODO: should use beautifulsoup massage
83
html = re.sub(r'(</SCR.*?)...(.*?IPT>)', r'\1\2', html)
86
# saving torrents in dict
88
for link in soup.findAll('a', attrs={'href': re.compile('down.php')}):
89
torrent_url = 'http://www.newtorrents.info%s' % link.get('href')
90
release_name = link.parent.next.get('title')
92
seed = link.findNext('td', attrs={'class': re.compile('s')}).renderContents()
99
log.warning('Error converting seed value (%s) from newtorrents to integer.' % seed)
102
#TODO: also parse content_size and peers from results
103
if comparator.matches(release_name):
104
torrents.append(Entry(title=release_name, url=torrent_url, torrent_seeds=seed,
105
search_ratio=comparator.ratio(), search_sort=torrent_availability(seed, 0)))
107
log.debug('rejecting search result: %s !~ %s' % (release_name, name))
108
# sort with seed number Reverse order
109
torrents.sort(reverse=True, key=lambda x: x.get('search_sort', 0))
112
dashindex = name.rfind('-')
114
return self.entries_from_search(name[:dashindex], comparator=comparator)
116
raise PluginWarning('No matches for %s' % name, log, log_once=True)
118
if len(torrents) == 1:
119
log.debug('found only one matching search result.')
121
log.debug('search result contains multiple matches, sorted %s by most seeders' % torrents)
124
register_plugin(NewTorrents, 'newtorrents', groups=['urlrewriter', 'search'])