Status: | Merged |
---|---|
Merged at revision: | 13729 |
Proposed branch: | lp:~tomek3d/calibre/store |
Merge into: | lp:calibre |
Diff against target: |
303 lines (+109/-107) 4 files modified
src/calibre/customize/builtins.py (+11/-11) src/calibre/gui2/store/stores/gandalf_plugin.py (+0/-82) src/calibre/gui2/store/stores/legimi_plugin.py (+18/-14) src/calibre/gui2/store/stores/publio_plugin.py (+80/-0) |
To merge this branch: | bzr merge lp:~tomek3d/calibre/store |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kovid Goyal | Pending | ||
Review via email: mp+135792@code.launchpad.net |
Commit message
Description of the change
Publio added, Legimi updated, Gandalf removed.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/calibre/customize/builtins.py' | |||
2 | --- src/calibre/customize/builtins.py 2012-11-20 10:47:44 +0000 | |||
3 | +++ src/calibre/customize/builtins.py 2012-11-22 22:41:20 +0000 | |||
4 | @@ -1433,15 +1433,6 @@ | |||
5 | 1433 | formats = ['EPUB', 'PDF'] | 1433 | formats = ['EPUB', 'PDF'] |
6 | 1434 | affiliate = True | 1434 | affiliate = True |
7 | 1435 | 1435 | ||
8 | 1436 | class StoreGandalfStore(StoreBase): | ||
9 | 1437 | name = 'Gandalf' | ||
10 | 1438 | author = u'Tomasz Długosz' | ||
11 | 1439 | description = u'Księgarnia internetowa Gandalf.' | ||
12 | 1440 | actual_plugin = 'calibre.gui2.store.stores.gandalf_plugin:GandalfStore' | ||
13 | 1441 | |||
14 | 1442 | headquarters = 'PL' | ||
15 | 1443 | formats = ['EPUB', 'PDF'] | ||
16 | 1444 | |||
17 | 1445 | class StoreGoogleBooksStore(StoreBase): | 1436 | class StoreGoogleBooksStore(StoreBase): |
18 | 1446 | name = 'Google Books' | 1437 | name = 'Google Books' |
19 | 1447 | description = u'Google Books' | 1438 | description = u'Google Books' |
20 | @@ -1472,7 +1463,7 @@ | |||
21 | 1472 | class StoreLegimiStore(StoreBase): | 1463 | class StoreLegimiStore(StoreBase): |
22 | 1473 | name = 'Legimi' | 1464 | name = 'Legimi' |
23 | 1474 | author = u'Tomasz Długosz' | 1465 | author = u'Tomasz Długosz' |
25 | 1475 | description = u'Tanie oraz darmowe ebooki, egazety i blogi w formacie EPUB, wprost na Twój e-czytnik, iPhone, iPad, Android i komputer' | 1466 | description = u'Ebooki w formacie EPUB, MOBI i PDF' |
26 | 1476 | actual_plugin = 'calibre.gui2.store.stores.legimi_plugin:LegimiStore' | 1467 | actual_plugin = 'calibre.gui2.store.stores.legimi_plugin:LegimiStore' |
27 | 1477 | 1468 | ||
28 | 1478 | headquarters = 'PL' | 1469 | headquarters = 'PL' |
29 | @@ -1566,6 +1557,15 @@ | |||
30 | 1566 | headquarters = 'US' | 1557 | headquarters = 'US' |
31 | 1567 | formats = ['EPUB', 'MOBI', 'PDF'] | 1558 | formats = ['EPUB', 'MOBI', 'PDF'] |
32 | 1568 | 1559 | ||
33 | 1560 | class StorePublioStore(StoreBase): | ||
34 | 1561 | name = 'Publio' | ||
35 | 1562 | description = u'Publio.pl to księgarnia internetowa, w której mogą Państwo nabyć e-booki i audiobooki.' | ||
36 | 1563 | actual_plugin = 'calibre.gui2.store.stores.publio_plugin:PublioStore' | ||
37 | 1564 | author = u'Tomasz Długosz' | ||
38 | 1565 | |||
39 | 1566 | headquarters = 'PL' | ||
40 | 1567 | formats = ['EPUB', 'MOBI', 'PDF'] | ||
41 | 1568 | |||
42 | 1569 | class StoreRW2010Store(StoreBase): | 1569 | class StoreRW2010Store(StoreBase): |
43 | 1570 | name = 'RW2010' | 1570 | name = 'RW2010' |
44 | 1571 | description = u'Polski serwis self-publishingowy. Pliki PDF, EPUB i MOBI. Maksymalna cena utworu nie przekracza u nas 10 złotych!' | 1571 | description = u'Polski serwis self-publishingowy. Pliki PDF, EPUB i MOBI. Maksymalna cena utworu nie przekracza u nas 10 złotych!' |
45 | @@ -1675,7 +1675,6 @@ | |||
46 | 1675 | StoreEscapeMagazineStore, | 1675 | StoreEscapeMagazineStore, |
47 | 1676 | StoreFeedbooksStore, | 1676 | StoreFeedbooksStore, |
48 | 1677 | StoreFoylesUKStore, | 1677 | StoreFoylesUKStore, |
49 | 1678 | StoreGandalfStore, | ||
50 | 1679 | StoreGoogleBooksStore, | 1678 | StoreGoogleBooksStore, |
51 | 1680 | StoreGutenbergStore, | 1679 | StoreGutenbergStore, |
52 | 1681 | StoreKoboStore, | 1680 | StoreKoboStore, |
53 | @@ -1689,6 +1688,7 @@ | |||
54 | 1689 | StoreOpenBooksStore, | 1688 | StoreOpenBooksStore, |
55 | 1690 | StoreOzonRUStore, | 1689 | StoreOzonRUStore, |
56 | 1691 | StorePragmaticBookshelfStore, | 1690 | StorePragmaticBookshelfStore, |
57 | 1691 | StorePublioStore, | ||
58 | 1692 | StoreRW2010Store, | 1692 | StoreRW2010Store, |
59 | 1693 | StoreSmashwordsStore, | 1693 | StoreSmashwordsStore, |
60 | 1694 | StoreVirtualoStore, | 1694 | StoreVirtualoStore, |
61 | 1695 | 1695 | ||
62 | === removed file 'src/calibre/gui2/store/stores/gandalf_plugin.py' | |||
63 | --- src/calibre/gui2/store/stores/gandalf_plugin.py 2012-01-30 21:43:19 +0000 | |||
64 | +++ src/calibre/gui2/store/stores/gandalf_plugin.py 1970-01-01 00:00:00 +0000 | |||
65 | @@ -1,82 +0,0 @@ | |||
66 | 1 | # -*- coding: utf-8 -*- | ||
67 | 2 | |||
68 | 3 | from __future__ import (unicode_literals, division, absolute_import, print_function) | ||
69 | 4 | |||
70 | 5 | __license__ = 'GPL 3' | ||
71 | 6 | __copyright__ = '2011-2012, Tomasz Długosz <tomek3d@gmail.com>' | ||
72 | 7 | __docformat__ = 'restructuredtext en' | ||
73 | 8 | |||
74 | 9 | import re | ||
75 | 10 | import urllib | ||
76 | 11 | from contextlib import closing | ||
77 | 12 | |||
78 | 13 | from lxml import html | ||
79 | 14 | |||
80 | 15 | from PyQt4.Qt import QUrl | ||
81 | 16 | |||
82 | 17 | from calibre import browser, url_slash_cleaner | ||
83 | 18 | from calibre.gui2 import open_url | ||
84 | 19 | from calibre.gui2.store import StorePlugin | ||
85 | 20 | from calibre.gui2.store.basic_config import BasicStoreConfig | ||
86 | 21 | from calibre.gui2.store.search_result import SearchResult | ||
87 | 22 | from calibre.gui2.store.web_store_dialog import WebStoreDialog | ||
88 | 23 | |||
89 | 24 | class GandalfStore(BasicStoreConfig, StorePlugin): | ||
90 | 25 | |||
91 | 26 | def open(self, parent=None, detail_item=None, external=False): | ||
92 | 27 | url = 'http://www.gandalf.com.pl/ebooks/' | ||
93 | 28 | |||
94 | 29 | if external or self.config.get('open_external', False): | ||
95 | 30 | open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) | ||
96 | 31 | else: | ||
97 | 32 | d = WebStoreDialog(self.gui, url, parent, detail_item) | ||
98 | 33 | d.setWindowTitle(self.name) | ||
99 | 34 | d.set_tags(self.config.get('tags', '')) | ||
100 | 35 | d.exec_() | ||
101 | 36 | |||
102 | 37 | def search(self, query, max_results=10, timeout=60): | ||
103 | 38 | counter = max_results | ||
104 | 39 | page = 1 | ||
105 | 40 | url = 'http://www.gandalf.com.pl/we/' + urllib.quote_plus(query.decode('utf-8').encode('iso8859_2')) + '/bdb' | ||
106 | 41 | |||
107 | 42 | br = browser() | ||
108 | 43 | |||
109 | 44 | while counter: | ||
110 | 45 | with closing(br.open((url + str(page-1) + '/#s') if (page-1) else (url + '/#s'), timeout=timeout)) as f: | ||
111 | 46 | doc = html.fromstring(f.read()) | ||
112 | 47 | for data in doc.xpath('//div[@class="box"]'): | ||
113 | 48 | if counter <= 0: | ||
114 | 49 | break | ||
115 | 50 | |||
116 | 51 | id = ''.join(data.xpath('.//div[@class="info"]/h3/a/@href')) | ||
117 | 52 | if not id: | ||
118 | 53 | continue | ||
119 | 54 | |||
120 | 55 | cover_url = ''.join(data.xpath('.//div[@class="info"]/h3/a/@id')) | ||
121 | 56 | title = ''.join(data.xpath('.//div[@class="info"]/h3/a/@title')) | ||
122 | 57 | formats = ''.join(data.xpath('.//div[@class="info"]/p[1]/text()')) | ||
123 | 58 | formats = re.findall(r'\((.*?)\)',formats)[0] | ||
124 | 59 | author = ''.join(data.xpath('.//div[@class="info"]/h4/text() | .//div[@class="info"]/h4/span/text()')) | ||
125 | 60 | price = ''.join(data.xpath('.//div[@class="options"]/h3/text()')) | ||
126 | 61 | price = re.sub('PLN', 'zł', price) | ||
127 | 62 | price = re.sub('\.', ',', price) | ||
128 | 63 | drm = data.xpath('boolean(.//div[@class="info" and contains(., "Zabezpieczenie: DRM")])') | ||
129 | 64 | |||
130 | 65 | counter -= 1 | ||
131 | 66 | |||
132 | 67 | s = SearchResult() | ||
133 | 68 | s.cover_url = 'http://imguser.gandalf.com.pl/' + re.sub('p', 'p_', cover_url) + '.jpg' | ||
134 | 69 | s.title = title.strip() | ||
135 | 70 | s.author = author.strip() | ||
136 | 71 | s.price = price | ||
137 | 72 | s.detail_item = id.strip() | ||
138 | 73 | if drm: | ||
139 | 74 | s.drm = SearchResult.DRM_LOCKED | ||
140 | 75 | else: | ||
141 | 76 | s.drm = SearchResult.DRM_UNLOCKED | ||
142 | 77 | s.formats = formats.upper().strip() | ||
143 | 78 | |||
144 | 79 | yield s | ||
145 | 80 | if not doc.xpath('boolean(//div[@class="wyszukiwanie_podstawowe_header"]//div[@class="box"])'): | ||
146 | 81 | break | ||
147 | 82 | page+=1 | ||
148 | 83 | 0 | ||
149 | === modified file 'src/calibre/gui2/store/stores/legimi_plugin.py' | |||
150 | --- src/calibre/gui2/store/stores/legimi_plugin.py 2012-08-15 20:09:42 +0000 | |||
151 | +++ src/calibre/gui2/store/stores/legimi_plugin.py 2012-11-22 22:41:20 +0000 | |||
152 | @@ -25,7 +25,7 @@ | |||
153 | 25 | 25 | ||
154 | 26 | def open(self, parent=None, detail_item=None, external=False): | 26 | def open(self, parent=None, detail_item=None, external=False): |
155 | 27 | 27 | ||
157 | 28 | plain_url = 'http://www.legimi.com/pl/ebooks/?price=any' | 28 | plain_url = 'http://www.legimi.com/pl/ebooki/' |
158 | 29 | url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + plain_url + ')' | 29 | url = 'https://ssl.afiliant.com/affskrypt,,2f9de2,,11483,,,?u=(' + plain_url + ')' |
159 | 30 | detail_url = None | 30 | detail_url = None |
160 | 31 | 31 | ||
161 | @@ -41,32 +41,36 @@ | |||
162 | 41 | d.exec_() | 41 | d.exec_() |
163 | 42 | 42 | ||
164 | 43 | def search(self, query, max_results=10, timeout=60): | 43 | def search(self, query, max_results=10, timeout=60): |
166 | 44 | url = 'http://www.legimi.com/pl/ebooks/?price=any&lang=pl&search=' + urllib.quote_plus(query) + '&sort=relevance' | 44 | url = 'http://www.legimi.com/pl/ebooki/?szukaj=' + urllib.quote_plus(query) |
167 | 45 | 45 | ||
168 | 46 | br = browser() | 46 | br = browser() |
170 | 47 | drm_pattern = re.compile("(DRM)") | 47 | drm_pattern = re.compile("zabezpieczona DRM") |
171 | 48 | 48 | ||
172 | 49 | counter = max_results | 49 | counter = max_results |
173 | 50 | with closing(br.open(url, timeout=timeout)) as f: | 50 | with closing(br.open(url, timeout=timeout)) as f: |
174 | 51 | doc = html.fromstring(f.read()) | 51 | doc = html.fromstring(f.read()) |
176 | 52 | for data in doc.xpath('//div[@class="list"]/ul/li'): | 52 | for data in doc.xpath('//div[@id="listBooks"]/div'): |
177 | 53 | if counter <= 0: | 53 | if counter <= 0: |
178 | 54 | break | 54 | break |
179 | 55 | 55 | ||
181 | 56 | id = ''.join(data.xpath('.//div[@class="item_cover_container"]/a[1]/@href')) | 56 | id = ''.join(data.xpath('.//a[@class="plainLink"]/@href')) |
182 | 57 | if not id: | 57 | if not id: |
183 | 58 | continue | 58 | continue |
184 | 59 | 59 | ||
188 | 60 | cover_url = ''.join(data.xpath('.//div[@class="item_cover_container"]/a/img/@src')) | 60 | cover_url = ''.join(data.xpath('.//img[1]/@src')) |
189 | 61 | title = ''.join(data.xpath('.//div[@class="item_entries"]/h2/a/text()')) | 61 | title = ''.join(data.xpath('.//span[@class="bookListTitle ellipsis"]/text()')) |
190 | 62 | author = ''.join(data.xpath('.//div[@class="item_entries"]/span[1]/a/text()')) | 62 | author = ''.join(data.xpath('.//span[@class="bookListAuthor ellipsis"]/text()')) |
191 | 63 | author = re.sub(',','',author) | 63 | author = re.sub(',','',author) |
192 | 64 | author = re.sub(';',',',author) | 64 | author = re.sub(';',',',author) |
198 | 65 | price = ''.join(data.xpath('.//span[@class="ebook_price"]/text()')) | 65 | price = ''.join(data.xpath('.//div[@class="bookListPrice"]/span/text()')) |
199 | 66 | formats = ''.join(data.xpath('.//div[@class="item_entries"]/span[3]/text()')) | 66 | formats = [] |
200 | 67 | formats = re.sub('Format:','',formats) | 67 | with closing(br.open(id.strip(), timeout=timeout/4)) as nf: |
201 | 68 | drm = drm_pattern.search(formats) | 68 | idata = html.fromstring(nf.read()) |
202 | 69 | formats = re.sub('\(DRM\)','',formats) | 69 | formatlist = idata.xpath('.//div[@id="fullBookFormats"]//span[@class="bookFormat"]/text()') |
203 | 70 | for x in formatlist: | ||
204 | 71 | if x.strip() not in formats: | ||
205 | 72 | formats.append(x.strip()) | ||
206 | 73 | drm = drm_pattern.search(''.join(idata.xpath('.//div[@id="fullBookFormats"]/p/text()'))) | ||
207 | 70 | 74 | ||
208 | 71 | counter -= 1 | 75 | counter -= 1 |
209 | 72 | 76 | ||
210 | @@ -76,7 +80,7 @@ | |||
211 | 76 | s.author = author.strip() | 80 | s.author = author.strip() |
212 | 77 | s.price = price | 81 | s.price = price |
213 | 78 | s.detail_item = 'http://www.legimi.com/' + id.strip() | 82 | s.detail_item = 'http://www.legimi.com/' + id.strip() |
214 | 83 | s.formats = ', '.join(formats) | ||
215 | 79 | s.drm = SearchResult.DRM_LOCKED if drm else SearchResult.DRM_UNLOCKED | 84 | s.drm = SearchResult.DRM_LOCKED if drm else SearchResult.DRM_UNLOCKED |
216 | 80 | s.formats = formats.strip() | ||
217 | 81 | 85 | ||
218 | 82 | yield s | 86 | yield s |
219 | 83 | 87 | ||
220 | === added file 'src/calibre/gui2/store/stores/publio_plugin.py' | |||
221 | --- src/calibre/gui2/store/stores/publio_plugin.py 1970-01-01 00:00:00 +0000 | |||
222 | +++ src/calibre/gui2/store/stores/publio_plugin.py 2012-11-22 22:41:20 +0000 | |||
223 | @@ -0,0 +1,80 @@ | |||
224 | 1 | # -*- coding: utf-8 -*- | ||
225 | 2 | |||
226 | 3 | from __future__ import (unicode_literals, division, absolute_import, print_function) | ||
227 | 4 | |||
228 | 5 | __license__ = 'GPL 3' | ||
229 | 6 | __copyright__ = '2012, Tomasz Długosz <tomek3d@gmail.com>' | ||
230 | 7 | __docformat__ = 'restructuredtext en' | ||
231 | 8 | |||
232 | 9 | import re | ||
233 | 10 | import urllib | ||
234 | 11 | from contextlib import closing | ||
235 | 12 | |||
236 | 13 | from lxml import html | ||
237 | 14 | |||
238 | 15 | from PyQt4.Qt import QUrl | ||
239 | 16 | |||
240 | 17 | from calibre import browser, url_slash_cleaner | ||
241 | 18 | from calibre.gui2 import open_url | ||
242 | 19 | from calibre.gui2.store import StorePlugin | ||
243 | 20 | from calibre.gui2.store.basic_config import BasicStoreConfig | ||
244 | 21 | from calibre.gui2.store.search_result import SearchResult | ||
245 | 22 | from calibre.gui2.store.web_store_dialog import WebStoreDialog | ||
246 | 23 | |||
247 | 24 | class PublioStore(BasicStoreConfig, StorePlugin): | ||
248 | 25 | |||
249 | 26 | def open(self, parent=None, detail_item=None, external=False): | ||
250 | 27 | google_analytics = '?utm_source=tdcalibre&utm_medium=calibre' | ||
251 | 28 | url = 'http://www.publio.pl/e-booki.html' + google_analytics | ||
252 | 29 | |||
253 | 30 | if external or self.config.get('open_external', False): | ||
254 | 31 | open_url(QUrl(url_slash_cleaner((detail_item + google_analytics) if detail_item else url))) | ||
255 | 32 | else: | ||
256 | 33 | d = WebStoreDialog(self.gui, url, parent, detail_item) | ||
257 | 34 | d.setWindowTitle(self.name) | ||
258 | 35 | d.set_tags(self.config.get('tags', '')) | ||
259 | 36 | d.exec_() | ||
260 | 37 | |||
261 | 38 | def search(self, query, max_results=20, timeout=60): | ||
262 | 39 | |||
263 | 40 | br = browser() | ||
264 | 41 | |||
265 | 42 | counter = max_results | ||
266 | 43 | page = 1 | ||
267 | 44 | while counter: | ||
268 | 45 | with closing(br.open('http://www.publio.pl/e-booki,strona' + str(page) + '.html?q=' + urllib.quote(query), timeout=timeout)) as f: | ||
269 | 46 | doc = html.fromstring(f.read()) | ||
270 | 47 | for data in doc.xpath('//div[@class="item"]'): | ||
271 | 48 | if counter <= 0: | ||
272 | 49 | break | ||
273 | 50 | |||
274 | 51 | id = ''.join(data.xpath('.//div[@class="img"]/a/@href')) | ||
275 | 52 | if not id: | ||
276 | 53 | continue | ||
277 | 54 | |||
278 | 55 | cover_url = ''.join(data.xpath('.//div[@class="img"]/a/img/@data-original')) | ||
279 | 56 | title = ''.join(data.xpath('.//div[@class="desc"]/h4/a/text()')) | ||
280 | 57 | title2 = ''.join(data.xpath('.//div[@class="desc"]/h5/a/text()')) | ||
281 | 58 | if title2: | ||
282 | 59 | title = title + '. ' + title2 | ||
283 | 60 | author = ', '.join(data.xpath('./div[@class="desc"]/div[@class="detailShortList"]/div[@class="row"]/a/text()')) | ||
284 | 61 | price = ''.join(data.xpath('.//div[@class="priceBoxContener "]/div/ins/text()')) | ||
285 | 62 | if not price: | ||
286 | 63 | price = ''.join(data.xpath('.//div[@class="priceBoxContener "]/div/text()')) | ||
287 | 64 | formats = ', '.join(data.xpath('.//div[@class="formats"]/a/img/@alt')) | ||
288 | 65 | |||
289 | 66 | counter -= 1 | ||
290 | 67 | |||
291 | 68 | s = SearchResult() | ||
292 | 69 | s.cover_url = 'http://www.publio.pl' + cover_url | ||
293 | 70 | s.title = title.strip() | ||
294 | 71 | s.author = author.strip() | ||
295 | 72 | s.price = price.strip() | ||
296 | 73 | s.detail_item = 'http://www.publio.pl' + id.strip() | ||
297 | 74 | s.drm = SearchResult.DRM_LOCKED if 'DRM' in formats else SearchResult.DRM_UNLOCKED | ||
298 | 75 | s.formats = formats.replace(' DRM','').strip() | ||
299 | 76 | |||
300 | 77 | yield s | ||
301 | 78 | if not doc.xpath('boolean(//a[@class="next"])'): | ||
302 | 79 | break | ||
303 | 80 | page+=1 |