Added a Batoto library.
[automanga.git] / manga / batoto.py
1 import urllib, re, BeautifulSoup
2 import lib, htcache
3 soup = BeautifulSoup.BeautifulSoup
4
5 def byclass(el, name, cl):
6     for ch in el.findAll(name):
7         if not isinstance(ch, BeautifulSoup.Tag): continue
8         cll = ch.get("class", "")
9         if cl in cll.split():
10             return ch
11     return None
12
13 def nextel(el):
14     while True:
15         el = el.nextSibling
16         if isinstance(el, BeautifulSoup.Tag):
17             return el
18
19 class page(lib.page):
20     def __init__(self, chapter, stack, n, url):
21         self.stack = stack
22         self.chapter = chapter
23         self.n = n
24         self.id = str(n)
25         self.name = u"Page %s" % n
26         self.url = url
27         self.ciurl = None
28
29     def iurl(self):
30         if self.ciurl is None:
31             page = soup(htcache.fetch(self.url))
32             img = nextel(page.find("div", id="full_image")).img
33             self.ciurl = img["src"].encode("us-ascii")
34         return self.ciurl
35
36     def open(self):
37         return lib.stdimgstream(self.iurl())
38
39     def __str__(self):
40         return self.name
41
42     def __repr(self):
43         return "<batoto.page %r.%r.%r>" % (self.chapter.manga.name, self.chapter.name, self.name)
44
45 class chapter(lib.pagelist):
46     def __init__(self, manga, stack, id, name, url):
47         self.stack = stack
48         self.manga = manga
49         self.id = id
50         self.name = name
51         self.url = url
52         self.cpag = None
53
54     def __getitem__(self, i):
55         return self.pages()[i]
56
57     def __len__(self):
58         return len(self.pages())
59
60     pnre = re.compile(r"page (\d+)")
61     def pages(self):
62         if self.cpag is None:
63             pg = soup(htcache.fetch(self.url))
64             cpag = []
65             for opt in pg.find("select", id="page_select").findAll("option"):
66                 url = opt["value"].encode("us-ascii")
67                 n = int(self.pnre.match(opt.string).group(1))
68                 cpag.append(page(self, self.stack + [(self, len(cpag))], n, url))
69             self.cpag = cpag
70         return self.cpag
71
72     def __str__(self):
73         return self.name
74
75     def __repr__(self):
76         return "<batoto.chapter %r.%r>" % (self.manga.name, self.name)
77
78 class manga(lib.manga):
79     def __init__(self, lib, id, name, url):
80         self.lib = lib
81         self.id = id
82         self.name = name
83         self.url = url
84         self.cch = None
85         self.stack = []
86
87     def __getitem__(self, i):
88         return self.ch()[i]
89
90     def __len__(self):
91         return len(self.ch())
92
93     cure = re.compile(r"/read/_/(\d+)/[^/]*")
94     def ch(self):
95         if self.cch is None:
96             page = soup(htcache.fetch(self.url))
97             cls = byclass(page, u"table", u"chapters_list")
98             if cls.tbody is not None:
99                 cls = cls.tbody
100             scl = u"lang_" + self.lib.lang
101             cch = []
102             for ch in cls.childGenerator():
103                 if isinstance(ch, BeautifulSoup.Tag) and ch.name == u"tr":
104                     cll = ch.get("class", "").split()
105                     if u"row" in cll and scl in cll:
106                         url = ch.td.a["href"].encode("us-ascii")
107                         m = self.cure.search(url)
108                         if m is None: raise Exception("Got weird chapter URL: %r" % url)
109                         cid = m.group(1)
110                         url = self.lib.base + "read/_/" + cid
111                         name = ch.td.a.text
112                         cch.append(chapter(self, [(self, len(cch))], cid, name, url))
113             cch.reverse()
114             self.cch = cch
115         return self.cch
116
117     def __str__(self):
118         return self.name
119
120     def __repr__(self):
121         return "<batoto.manga %r>" % self.name
122
123 class library(lib.library):
124     def __init__(self):
125         self.base = "http://www.batoto.net/"
126         self.lang = u"English"
127
128     def byid(self, id):
129         url = self.base + "comic/_/comics/" + id
130         page = soup(htcache.fetch(url))
131         title = page.find("h1", attrs={"class": "ipsType_pagetitle"})
132         if title is None:
133             raise KeyError(id)
134         return manga(self, id, title.string.strip(), url)
135
136     mure = re.compile(r"/comic/_/comics/([^/]*)$")
137     def search(self, expr):
138         resp = urllib.urlopen(self.base + "forums/index.php?app=core&module=search&do=search&fromMainBar=1",
139                               urllib.urlencode({"search_term": expr, "search_app": "ccs:database:3"}))
140         try:
141             page = soup(resp.read())
142         finally:
143             resp.close()
144         ret = []
145         for child in page.find("div", id="search_results").ol.childGenerator():
146             if isinstance(child, BeautifulSoup.Tag) and child.name == u"li":
147                 info = child.find("div", attrs={"class": "result_info"})
148                 url = info.h3.a["href"].encode("us-ascii")
149                 m = self.mure.search(url)
150                 if m is None: raise Exception("Got weird manga URL: %r" % url)
151                 id = m.group(1)
152                 name = info.h3.a.string.strip()
153                 ret.append(manga(self, id, name, url))
154         return ret