mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Merge remote-tracking branch 'kovid/master'
This commit is contained in:
commit
6748b97ea0
@ -400,6 +400,17 @@ If you use this tool multiple times, each invocation will cause the previously
|
|||||||
created inline Table of Contents to be replaced. The tool can be accessed via
|
created inline Table of Contents to be replaced. The tool can be accessed via
|
||||||
:guilabel:`Tools->Table of Contents->Insert inline Table of Contents`.
|
:guilabel:`Tools->Table of Contents->Insert inline Table of Contents`.
|
||||||
|
|
||||||
|
Filter style information
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This tool can be used to easily remove specified CSS style properties from the
|
||||||
|
entire book. You can tell it what properties you want removed, for example,
|
||||||
|
``color, background-color, line-height`` and it will remove them from
|
||||||
|
everywhere they occur --- stylesheets, ``<style>`` tags and inline ``style``
|
||||||
|
attributes. After removing the style information, a summary of all the changes
|
||||||
|
made is displayed so you can see exactly what was changed. The tool can be
|
||||||
|
accessed via :guilabel:`Tools->Filter style information`.
|
||||||
|
|
||||||
.. _checkpoints:
|
.. _checkpoints:
|
||||||
|
|
||||||
Checkpoints
|
Checkpoints
|
||||||
|
@ -250,6 +250,11 @@ The following functions are available in addition to those described in single-f
|
|||||||
* ``divide(x, y)`` -- returns x / y. Throws an exception if either x or y are not numbers.
|
* ``divide(x, y)`` -- returns x / y. Throws an exception if either x or y are not numbers.
|
||||||
* ``eval(string)`` -- evaluates the string as a program, passing the local variables (those ``assign`` ed to). This permits using the template processor to construct complex results from local variables. Because the `{` and `}` characters are special, you must use `[[` for the `{` character and `]]` for the '}' character; they are converted automatically. Note also that prefixes and suffixes (the `|prefix|suffix` syntax) cannot be used in the argument to this function when using template program mode.
|
* ``eval(string)`` -- evaluates the string as a program, passing the local variables (those ``assign`` ed to). This permits using the template processor to construct complex results from local variables. Because the `{` and `}` characters are special, you must use `[[` for the `{` character and `]]` for the '}' character; they are converted automatically. Note also that prefixes and suffixes (the `|prefix|suffix` syntax) cannot be used in the argument to this function when using template program mode.
|
||||||
* ``field(name)`` -- returns the metadata field named by ``name``.
|
* ``field(name)`` -- returns the metadata field named by ``name``.
|
||||||
|
* ``first_matching_cmp(val, cmp1, result1, cmp2, r2, ..., else_result)`` -- compares "val < cmpN" in sequence, returning resultN for the first comparison that succeeds. Returns else_result if no comparison succeeds. Example::
|
||||||
|
|
||||||
|
``first_matching_cmp(10,5,"small",10,"middle",15,"large","giant")``
|
||||||
|
|
||||||
|
returns "middle". The same example with a first value of 16 returns "giant".
|
||||||
* ``first_non_empty(value, value, ...)`` -- returns the first value that is not empty. If all values are empty, then the empty value is returned. You can have as many values as you want.
|
* ``first_non_empty(value, value, ...)`` -- returns the first value that is not empty. If all values are empty, then the empty value is returned. You can have as many values as you want.
|
||||||
* ``format_date(x, date_format)`` -- format_date(val, format_string) -- format the value, which must be a date field, using the format_string, returning a string. The formatting codes are::
|
* ``format_date(x, date_format)`` -- format_date(val, format_string) -- format the value, which must be a date field, using the format_string, returning a string. The formatting codes are::
|
||||||
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
http://ameblo.jp/
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
|
||||||
|
|
||||||
class SakuraBlog(BasicNewsRecipe):
|
|
||||||
title = u'chou chou blog'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
oldest_article = 4
|
|
||||||
publication_type = 'blog'
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
description = 'Japanese popular dog blog'
|
|
||||||
publisher = ''
|
|
||||||
category = 'dog, pet, japan'
|
|
||||||
language = 'ja'
|
|
||||||
encoding = 'utf-8'
|
|
||||||
use_embedded_content = True
|
|
||||||
|
|
||||||
feeds = [(u'blog', u'http://feedblog.ameba.jp/rss/ameblo/chouchou1218/rss20.xml')]
|
|
||||||
|
|
||||||
def parse_feeds(self):
|
|
||||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
|
||||||
for curfeed in feeds:
|
|
||||||
delList = []
|
|
||||||
for a,curarticle in enumerate(curfeed.articles):
|
|
||||||
if re.search(r'rssad.jp', curarticle.url):
|
|
||||||
delList.append(curarticle)
|
|
||||||
if len(delList)>0:
|
|
||||||
for d in delList:
|
|
||||||
index = curfeed.articles.index(d)
|
|
||||||
curfeed.articles[index:index+1] = []
|
|
||||||
return feeds
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
japan.engadget.com
|
japan.engadget.com
|
||||||
'''
|
'''
|
||||||
@ -20,19 +20,20 @@ class EndgadgetJapan(BasicNewsRecipe):
|
|||||||
index = 'http://japanese.engadget.com/'
|
index = 'http://japanese.engadget.com/'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
|
||||||
remove_tags_before = dict(name="h1", attrs={'class':"post_title"})
|
remove_tags_before = dict(name="header", attrs={'class':"header"})
|
||||||
remove_tags_after = dict(name='div', attrs={'class':'post_body'})
|
remove_tags_after = dict(name='div', attrs={'class':'post-meta'})
|
||||||
|
|
||||||
def parse_index(self):
|
def parse_index(self):
|
||||||
feeds = []
|
feeds = []
|
||||||
newsarticles = []
|
newsarticles = []
|
||||||
soup = self.index_to_soup(self.index)
|
soup = self.index_to_soup(self.index)
|
||||||
for topstories in soup.findAll('div',attrs={'class':'post_content'}):
|
for topstories in soup.findAll('header',attrs={'class':'post-header'}):
|
||||||
itt = topstories.find('h4')
|
itt = topstories.find('h2')
|
||||||
itema = itt.find('a',href=True)
|
itema = itt.find('a',href=True)
|
||||||
|
itemtime = topstories.find('span',attrs={'class':'time'})
|
||||||
newsarticles.append({
|
newsarticles.append({
|
||||||
'title' :itema.string
|
'title' :itema.string
|
||||||
,'date' :''
|
,'date' :itemtime.string
|
||||||
,'url' :itema['href']
|
,'url' :itema['href']
|
||||||
,'description':''
|
,'description':''
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
www.kahoku.co.jp
|
www.kahoku.co.jp
|
||||||
'''
|
'''
|
||||||
@ -21,11 +21,5 @@ class KahokuShinpoNews(BasicNewsRecipe):
|
|||||||
|
|
||||||
feeds = [(u'news', u'http://www.kahoku.co.jp/rss/index_thk.xml')]
|
feeds = [(u'news', u'http://www.kahoku.co.jp/rss/index_thk.xml')]
|
||||||
|
|
||||||
keep_only_tags = [ dict(id="page_title"),
|
keep_only_tags = [ {'class':"category"},{'class':"ttl"},{'class':'photoimg'},{'class':"txt"},{'class':"data"}]
|
||||||
dict(id="news_detail"),
|
|
||||||
dict(id="bt_title"),
|
|
||||||
{'class':"photoLeft"},
|
|
||||||
dict(id="bt_body")
|
|
||||||
]
|
|
||||||
remove_tags = [ {'class':"button"}]
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
sankei.jp.msn.com
|
sankei.jp.msn.com
|
||||||
'''
|
'''
|
||||||
@ -20,5 +20,4 @@ class MSNSankeiNewsProduct(BasicNewsRecipe):
|
|||||||
|
|
||||||
feeds = [(u'\u65b0\u5546\u54c1', u'http://sankei.jp.msn.com/rss/news/release.xml')]
|
feeds = [(u'\u65b0\u5546\u54c1', u'http://sankei.jp.msn.com/rss/news/release.xml')]
|
||||||
|
|
||||||
remove_tags_before = dict(id="NewsTitle")
|
keep_only_tags = [dict(id=['MainContent'])]
|
||||||
remove_tags_after = dict(id="RelatedTitle")
|
|
||||||
|
@ -15,16 +15,10 @@ class NationalGeographicNews(BasicNewsRecipe):
|
|||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
auto_cleanup = True
|
||||||
|
|
||||||
feeds = [(u'news', u'http://feeds.nationalgeographic.com/ng/News/News_Main')]
|
feeds = [(u'news', u'http://feeds.nationalgeographic.com/ng/News/News_Main')]
|
||||||
|
|
||||||
remove_tags_before = dict(id='page_head')
|
|
||||||
remove_tags_after = [dict(id='social_buttons'),{'class':'aside'}]
|
|
||||||
remove_tags = [
|
|
||||||
{'class':'hidden'}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
def parse_feeds(self):
|
def parse_feeds(self):
|
||||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||||
for curfeed in feeds:
|
for curfeed in feeds:
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
class NikkeiNet_sub_economy(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u7d4c\u6e08)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
{'class':"cmn-article_list"},
|
|
||||||
dict(id="ABOUT-NIKKEI"),
|
|
||||||
{'class':"cmn-sub_market"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [ (u'\u653f\u6cbb', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=seiji'),
|
|
||||||
(u'\u8ca1\u52d9', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=zaimu'),
|
|
||||||
(u'\u7d4c\u6e08', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=keizai'),
|
|
||||||
(u'\u30de\u30fc\u30b1\u30c3\u30c8', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=market'),
|
|
||||||
(u'\u96c7\u7528', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=koyou'),
|
|
||||||
(u'\u6559\u80b2', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=kyouiku'),
|
|
||||||
(u'\u304a\u304f\u3084\u307f', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=okuyami'),
|
|
||||||
(u'\u4eba\u4e8b', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=zinzi'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
|||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
|
|
||||||
class NikkeiNet_sub_industory(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u7523\u696d)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [ (u'\u65e5\u7d4c\u4f01\u696d', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=sangyo'),
|
|
||||||
(u'\u65e5\u7d4c\u88fd\u54c1', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=newpro'),
|
|
||||||
(u'internet', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=internet'),
|
|
||||||
(u'\u56fd\u969b', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=kaigai'),
|
|
||||||
(u'\u79d1\u5b66', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=kagaku'),
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
|
|
||||||
class NikkeiNet_sub_life(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u751f\u6d3b)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [ (u'\u304f\u3089\u3057', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=kurashi'),
|
|
||||||
(u'\u30a8\u30b3', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=eco'),
|
|
||||||
(u'\u5065\u5eb7', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=kenkou'),
|
|
||||||
(u'\u7279\u96c6', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=special')
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
|
|
||||||
class NikkeiNet_sub_main(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u7dcf\u5408)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
{'class':"cmn-article_list"},
|
|
||||||
{'class':"cmn-dashedline"},
|
|
||||||
{'class':"cmn-hide"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [ (u'NIKKEI', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=main')]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
|
|
||||||
class NikkeiNet_sub_shakai(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(Social)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [
|
|
||||||
(u'\u793e\u4f1a', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=shakai')
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
|||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
|
||||||
'''
|
|
||||||
www.nikkei.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
import re
|
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
|
||||||
import mechanize
|
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
|
|
||||||
|
|
||||||
class NikkeiNet_sub_sports(BasicNewsRecipe):
|
|
||||||
title = u'\u65e5\u7d4c\u65b0\u805e\u96fb\u5b50\u7248(\u30b9\u30dd\u30fc\u30c4)'
|
|
||||||
__author__ = 'Hiroshi Miura'
|
|
||||||
description = 'News and current market affairs from Japan'
|
|
||||||
cover_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
masthead_url = 'http://parts.nikkei.com/parts/ds/images/common/logo_r1.svg'
|
|
||||||
needs_subscription = True
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 20
|
|
||||||
language = 'ja'
|
|
||||||
remove_javascript = False
|
|
||||||
temp_files = []
|
|
||||||
|
|
||||||
remove_tags_before = {'class':"cmn-section cmn-indent"}
|
|
||||||
remove_tags = [
|
|
||||||
{'class':"JSID_basePageMove JSID_baseAsyncSubmit cmn-form_area JSID_optForm_utoken"},
|
|
||||||
{'class':"cmn-article_keyword cmn-clearfix"},
|
|
||||||
{'class':"cmn-print_headline cmn-clearfix"},
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"cmn-pr_list"}
|
|
||||||
|
|
||||||
feeds = [
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u30d7\u30ed\u91ce\u7403', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=baseball'),
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u5927\u30ea\u30fc\u30b0', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=mlb'),
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u30b5\u30c3\u30ab\u30fc', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=soccer'),
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u30b4\u30eb\u30d5', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=golf'),
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u76f8\u64b2', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=sumou'),
|
|
||||||
(u'\u30b9\u30dd\u30fc\u30c4\uff1a\u7af6\u99ac', u'http://www.zou3.net/php/rss/nikkei2rss.php?head=keiba')
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_browser(self):
|
|
||||||
br = BasicNewsRecipe.get_browser(self)
|
|
||||||
|
|
||||||
cj = mechanize.LWPCookieJar()
|
|
||||||
br.set_cookiejar(cj)
|
|
||||||
|
|
||||||
#br.set_debug_http(True)
|
|
||||||
#br.set_debug_redirects(True)
|
|
||||||
#br.set_debug_responses(True)
|
|
||||||
|
|
||||||
if self.username is not None and self.password is not None:
|
|
||||||
#print "----------------------------get login form--------------------------------------------"
|
|
||||||
# open login form
|
|
||||||
br.open('https://id.nikkei.com/lounge/nl/base/LA0010.seam')
|
|
||||||
response = br.response()
|
|
||||||
#print "----------------------------get login form---------------------------------------------"
|
|
||||||
#print "----------------------------set login form---------------------------------------------"
|
|
||||||
# remove disabled input which brings error on mechanize
|
|
||||||
response.set_data(response.get_data().replace("<input id=\"j_id48\"", "<!-- "))
|
|
||||||
response.set_data(response.get_data().replace("gm_home_on.gif\" />", " -->"))
|
|
||||||
br.set_response(response)
|
|
||||||
br.select_form(name='LA0010Form01')
|
|
||||||
br['LA0010Form01:LA0010Email'] = self.username
|
|
||||||
br['LA0010Form01:LA0010Password'] = self.password
|
|
||||||
br.form.find_control(id='LA0010Form01:LA0010AutoLoginOn',type="checkbox").get(nr=0).selected = True
|
|
||||||
br.submit()
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------send login form---------------------------------------------"
|
|
||||||
#print "----------------------------open news main page-----------------------------------------"
|
|
||||||
# open news site
|
|
||||||
br.open('http://www.nikkei.com/')
|
|
||||||
br.response()
|
|
||||||
#print "----------------------------www.nikkei.com BODY --------------------------------------"
|
|
||||||
#print response2.get_data()
|
|
||||||
#print "-------------------------^^-got auto redirect form----^^--------------------------------"
|
|
||||||
# forced redirect in default
|
|
||||||
br.select_form(nr=0)
|
|
||||||
br.submit()
|
|
||||||
response3 = br.response()
|
|
||||||
# return some cookie which should be set by Javascript
|
|
||||||
#print response3.geturl()
|
|
||||||
raw = response3.get_data()
|
|
||||||
#print "---------------------------response to form --------------------------------------------"
|
|
||||||
# grab cookie from JS and set it
|
|
||||||
redirectflag = re.search(r"var checkValue = '(\d+)';", raw, re.M).group(1)
|
|
||||||
br.select_form(nr=0)
|
|
||||||
|
|
||||||
self.temp_files.append(PersistentTemporaryFile('_fa.html'))
|
|
||||||
self.temp_files[-1].write("#LWP-Cookies-2.0\n")
|
|
||||||
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: Cookie-dummy=Cookie-value; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].write("Set-Cookie3: redirectFlag="+redirectflag+"; domain=\".nikkei.com\"; path=\"/\"; path_spec; secure; expires=\"2029-12-21 05:07:59Z\"; version=0\n")
|
|
||||||
self.temp_files[-1].close()
|
|
||||||
cj.load(self.temp_files[-1].name)
|
|
||||||
|
|
||||||
br.submit()
|
|
||||||
|
|
||||||
#br.set_debug_http(False)
|
|
||||||
#br.set_debug_redirects(False)
|
|
||||||
#br.set_debug_responses(False)
|
|
||||||
return br
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
http://ameblo.jp/sauta19/
|
http://ameblo.jp/sauta19/
|
||||||
'''
|
'''
|
||||||
@ -18,7 +18,7 @@ class UniNoHimituKichiBlog(BasicNewsRecipe):
|
|||||||
category = 'cat, pet, japan'
|
category = 'cat, pet, japan'
|
||||||
language = 'ja'
|
language = 'ja'
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
|
keep_only_tags = [{'class':'entry_head'},{'class':'subContentsInner'}]
|
||||||
feeds = [(u'blog', u'http://feedblog.ameba.jp/rss/ameblo/sauta19/rss20.xml')]
|
feeds = [(u'blog', u'http://feedblog.ameba.jp/rss/ameblo/sauta19/rss20.xml')]
|
||||||
|
|
||||||
def parse_feeds(self):
|
def parse_feeds(self):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
www.yomiuri.co.jp
|
www.yomiuri.co.jp
|
||||||
'''
|
'''
|
||||||
@ -16,16 +16,13 @@ class YOLNews(BasicNewsRecipe):
|
|||||||
publisher = 'Yomiuri Online News'
|
publisher = 'Yomiuri Online News'
|
||||||
category = 'news, japan'
|
category = 'news, japan'
|
||||||
language = 'ja'
|
language = 'ja'
|
||||||
encoding = 'Shift_JIS'
|
encoding = 'UTF-8'
|
||||||
index = 'http://www.yomiuri.co.jp/latestnews/'
|
index = 'http://www.yomiuri.co.jp/latestnews/'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
masthead_title = u'YOMIURI ONLINE'
|
masthead_title = u'YOMIURI ONLINE'
|
||||||
|
|
||||||
keep_only_tags = [{'class':"article-def"}]
|
|
||||||
remove_tags = [{'class':"RelatedArticle"},
|
keep_only_tags = [{'class':"article text-resizeable"}]
|
||||||
{'class':"sbtns"}
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"date-def"}
|
|
||||||
|
|
||||||
def parse_feeds(self):
|
def parse_feeds(self):
|
||||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||||
@ -42,22 +39,22 @@ class YOLNews(BasicNewsRecipe):
|
|||||||
|
|
||||||
def parse_index(self):
|
def parse_index(self):
|
||||||
feeds = []
|
feeds = []
|
||||||
|
newsarticles = []
|
||||||
soup = self.index_to_soup(self.index)
|
soup = self.index_to_soup(self.index)
|
||||||
topstories = soup.find('ul',attrs={'class':'list-def'})
|
listlatest = soup.find('ul', attrs={'class':'list-common list-common-latest'})
|
||||||
if topstories:
|
if listlatest:
|
||||||
newsarticles = []
|
for itt in listlatest.findAll('li'):
|
||||||
for itt in topstories.findAll('li'):
|
itema = itt.find('a',href=True)
|
||||||
itema = itt.find('a',href=True)
|
if itema:
|
||||||
if itema:
|
item_headline = itema.find('span',attrs={'class':'headline'})
|
||||||
itd1 = itema.findNextSibling(text = True)
|
item_date = item_headline.find('span',attrs={'class':'update'})
|
||||||
itd2 = itd1.findNextSibling(text = True)
|
newsarticles.append({
|
||||||
itd3 = itd2.findNextSibling(text = True)
|
'title' :item_headline.contents[0]
|
||||||
newsarticles.append({
|
,'date' :item_date
|
||||||
'title' :itema.string
|
,'url' :itema['href']
|
||||||
,'date' :''.join([itd1, itd2, itd3])
|
,'description':''
|
||||||
,'url' :'http://www.yomiuri.co.jp' + itema['href']
|
})
|
||||||
,'description':''
|
feeds.append(('latest', newsarticles))
|
||||||
})
|
|
||||||
feeds.append(('latest', newsarticles))
|
|
||||||
return feeds
|
return feeds
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Hiroshi Miura <miurahr@linux.com>'
|
__copyright__ = '2010,2014, Hiroshi Miura <miurahr@linux.com>'
|
||||||
'''
|
'''
|
||||||
www.yomiuri.co.jp
|
www.yomiuri.co.jp
|
||||||
'''
|
'''
|
||||||
@ -16,16 +16,12 @@ class YOLNews(BasicNewsRecipe):
|
|||||||
publisher = 'Yomiuri Online News'
|
publisher = 'Yomiuri Online News'
|
||||||
category = 'news, japan'
|
category = 'news, japan'
|
||||||
language = 'ja'
|
language = 'ja'
|
||||||
encoding = 'Shift_JIS'
|
encoding = 'UTF-8'
|
||||||
index = 'http://www.yomiuri.co.jp/world/'
|
index = 'http://www.yomiuri.co.jp/world/'
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
masthead_title = u"YOMIURI ONLINE"
|
masthead_title = u"YOMIURI ONLINE"
|
||||||
|
|
||||||
keep_only_tags = [{'class':"article-def"}]
|
keep_only_tags = [{'class':"article text-resizeable"}]
|
||||||
remove_tags = [{'class':"RelatedArticle"},
|
|
||||||
{'class':"sbtns"}
|
|
||||||
]
|
|
||||||
remove_tags_after = {'class':"date-def"}
|
|
||||||
|
|
||||||
def parse_feeds(self):
|
def parse_feeds(self):
|
||||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||||
@ -42,20 +38,36 @@ class YOLNews(BasicNewsRecipe):
|
|||||||
|
|
||||||
def parse_index(self):
|
def parse_index(self):
|
||||||
feeds = []
|
feeds = []
|
||||||
|
newsarticles = []
|
||||||
soup = self.index_to_soup(self.index)
|
soup = self.index_to_soup(self.index)
|
||||||
topstories = soup.find('ul',attrs={'class':'list-def'})
|
mainspan = soup.find('div', attrs={'class':'pbNested span-main-inr'})
|
||||||
if topstories:
|
if mainspan:
|
||||||
newsarticles = []
|
topstories = mainspan.find('ul',attrs={'class':'list-top'})
|
||||||
for itt in topstories.findAll('li'):
|
if topstories:
|
||||||
itema = itt.find('a',href=True)
|
for itt in topstories.findAll('li'):
|
||||||
if itema:
|
itema = itt.find('a',href=True)
|
||||||
itd1 = itema.findNextSibling(text = True)
|
if itema:
|
||||||
newsarticles.append({
|
item_headline = itema.find('span',attrs={'class':'headline'})
|
||||||
'title' :itema.string
|
item_date = item_headline.find('span',attrs={'class':'update'})
|
||||||
,'date' :''.join([itd1])
|
newsarticles.append({
|
||||||
,'url' :'http://www.yomiuri.co.jp' + itema['href']
|
'title' :item_headline.contents[0]
|
||||||
,'description':''
|
,'date' :item_date
|
||||||
})
|
,'url' :itema['href']
|
||||||
feeds.append(('World', newsarticles))
|
,'description':''
|
||||||
|
})
|
||||||
|
secondstories = mainspan.find('ul', attrs={'class':'list-common'})
|
||||||
|
if secondstories:
|
||||||
|
for itt in secondstories.findAll('li'):
|
||||||
|
itema = itt.find('a',href=True)
|
||||||
|
if itema:
|
||||||
|
item_headline = itema.find('span',attrs={'class':'headline'})
|
||||||
|
item_date = item_headline.find('span',attrs={'class':'update'})
|
||||||
|
newsarticles.append({
|
||||||
|
'title' :item_headline.contents[0]
|
||||||
|
,'date' :item_date
|
||||||
|
,'url' :itema['href']
|
||||||
|
,'description':''
|
||||||
|
})
|
||||||
|
feeds.append(('World', newsarticles))
|
||||||
return feeds
|
return feeds
|
||||||
|
|
||||||
|
@ -1382,3 +1382,4 @@ application/vnd.ms-opentype otf
|
|||||||
application/font-woff woff
|
application/font-woff woff
|
||||||
application/x-font-truetype ttf
|
application/x-font-truetype ttf
|
||||||
text/xml plist
|
text/xml plist
|
||||||
|
application/x-ibooks+zip ibook
|
||||||
|
@ -41,10 +41,10 @@ Cygwin
|
|||||||
This is needed for automation of the build process, and the ease of use of the
|
This is needed for automation of the build process, and the ease of use of the
|
||||||
unix shell (bash).
|
unix shell (bash).
|
||||||
|
|
||||||
Install, vim, rsync, openssh, unzip, wget, make at a minimum.
|
Install vim, dos2unix, rsync, openssh, unzip, wget, make, zsh, bash-completion, curl at a minimum.
|
||||||
|
|
||||||
After installing python run::
|
After installing python run::
|
||||||
python setup/vcvars.py && echo 'source ~/.vcvars' >> ~/.bash_profile
|
python setup/vcvars.py && echo 'source ~/.vcvars' >> ~/.zshrc
|
||||||
|
|
||||||
To allow you to use the visual studio tools in the cygwin shell.
|
To allow you to use the visual studio tools in the cygwin shell.
|
||||||
|
|
||||||
@ -147,39 +147,334 @@ Put sqlite3*.h from the sqlite windows amalgamation in ~/sw/include
|
|||||||
APSW
|
APSW
|
||||||
-----
|
-----
|
||||||
|
|
||||||
Download source from http://code.google.com/p/apsw/downloads/list and run in visual studio prompt
|
Download source from http://code.google.com/p/apsw/downloads/list and run
|
||||||
|
|
||||||
python setup.py fetch --all --missing-checksum-ok build --enable-all-extensions install test
|
python setup.py fetch --all --missing-checksum-ok build --enable-all-extensions install test
|
||||||
|
|
||||||
|
Build requirements
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Install perl and ruby (needed to build openssl and qt):
|
||||||
|
Perl: http://www.activestate.com/activeperl
|
||||||
|
Ruby: http://rubyinstaller.org/
|
||||||
|
|
||||||
|
Put both perl.exe and ruby.exe in the PATH
|
||||||
|
|
||||||
|
Get nasm.exe from (needed for openssl and libjpeg-turbo)
|
||||||
|
http://www.nasm.us/pub/nasm/releasebuilds/2.11/win32/nasm-2.11-win32.zip
|
||||||
|
and put it in ~/sw/bin (which must be in PATH)
|
||||||
|
|
||||||
OpenSSL
|
OpenSSL
|
||||||
--------
|
--------
|
||||||
|
|
||||||
First install ActiveState Perl if you dont already have perl in windows
|
Download and untar the openssl tarball.
|
||||||
|
To install use a private prefix: --prefix=C:/cygwin64/home/kovid/sw/private/openssl
|
||||||
Then, get nasm.exe from
|
|
||||||
http://www.nasm.us/pub/nasm/releasebuilds/2.05/nasm-2.05-win32.zip and put it
|
|
||||||
somewhere on your PATH (I chose ~/sw/bin)
|
|
||||||
|
|
||||||
Download and untar the openssl tarball, follow the instructions in INSTALL.(W32|W64)
|
|
||||||
to install use prefix q:\openssl
|
|
||||||
|
|
||||||
The following *MUST BE RUN* in a Visual Studio Command prompt and not in a cygwin
|
The following *MUST BE RUN* in a Visual Studio Command prompt and not in a cygwin
|
||||||
environment.
|
environment.
|
||||||
|
|
||||||
For 32-bit::
|
For 32-bit::
|
||||||
perl Configure VC-WIN32 no-asm enable-static-engine --prefix=Q:/openssl
|
perl Configure VC-WIN32 no-asm enable-static-engine --prefix=C:/cygwin64/home/kovid/sw/private/openssl
|
||||||
ms\do_ms.bat
|
ms\do_ms.bat
|
||||||
nmake -f ms\ntdll.mak
|
nmake -f ms\ntdll.mak
|
||||||
nmake -f ms\ntdll.mak test
|
nmake -f ms\ntdll.mak test
|
||||||
nmake -f ms\ntdll.mak install
|
nmake -f ms\ntdll.mak install
|
||||||
|
|
||||||
For 64-bit::
|
For 64-bit::
|
||||||
perl Configure VC-WIN64A no-asm enable-static-engine --prefix=C:/cygwin/home/kovid/sw/private/openssl
|
perl Configure VC-WIN64A no-asm enable-static-engine --prefix=C:/cygwin64/home/kovid/sw/private/openssl
|
||||||
ms\do_win64a.bat
|
ms\do_win64a.bat
|
||||||
nmake -f ms\ntdll.mak
|
nmake -f ms\ntdll.mak
|
||||||
nmake -f ms\ntdll.mak test
|
nmake -f ms\ntdll.mak test
|
||||||
nmake -f ms\ntdll.mak install
|
nmake -f ms\ntdll.mak install
|
||||||
|
|
||||||
|
ICU
|
||||||
|
-------
|
||||||
|
|
||||||
|
Download the win32 *source* .zip from http://www.icu-project.org/download
|
||||||
|
|
||||||
|
Extract to C:\cygwin64\home\kovid\sw\private\icu
|
||||||
|
|
||||||
|
The following must be run in the VS Command Prompt, not the cygwin ssh shell
|
||||||
|
|
||||||
|
cd to <ICU>\source::
|
||||||
|
|
||||||
|
set PATH=%PATH%;C:\cygwin64\bin
|
||||||
|
dos2unix runConfigureICU
|
||||||
|
bash ./runConfigureICU Cygwin/MSVC
|
||||||
|
make
|
||||||
|
|
||||||
|
zlib
|
||||||
|
------
|
||||||
|
|
||||||
|
http://www.zlib.net/
|
||||||
|
|
||||||
|
Build with::
|
||||||
|
nmake -f win32/Makefile.msc
|
||||||
|
nmake -f win32/Makefile.msc test
|
||||||
|
cp zlib1.dll* ~/sw/bin && cp zlib.lib zdll.* ~/sw/lib/ && cp zconf.h zlib.h ~/sw/include/
|
||||||
|
|
||||||
|
jpeg-8
|
||||||
|
-------
|
||||||
|
|
||||||
|
Get the source code from: http://sourceforge.net/projects/libjpeg-turbo/files/
|
||||||
|
|
||||||
|
Run::
|
||||||
|
chmod +x cmakescripts/* && mkdir -p build && cd build
|
||||||
|
cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DWITH_JPEG8=1 ..
|
||||||
|
nmake
|
||||||
|
cp sharedlib/jpeg8.dll* ~/sw/bin/ && cp sharedlib/jpeg.lib ~/sw/lib/ && cp jconfig.h ../jerror.h ../jpeglib.h ../jmorecfg.h ~/sw/include
|
||||||
|
|
||||||
|
libpng
|
||||||
|
---------
|
||||||
|
|
||||||
|
Download the libpng .zip source file from:
|
||||||
|
http://www.libpng.org/pub/png/libpng.html
|
||||||
|
|
||||||
|
Run::
|
||||||
|
mkdir -p build && cd build
|
||||||
|
cmake -G "NMake Makefiles" -DPNG_SHARED=1 -DCMAKE_BUILD_TYPE=Release -DZLIB_INCLUDE_DIR=C:/cygwin64/home/kovid/sw/include -DZLIB_LIBRARY=C:/cygwin64/home/kovid/sw/lib/zdll.lib ..
|
||||||
|
nmake
|
||||||
|
cp libpng*.dll ~/sw/bin/ && cp libpng*.lib ~/sw/lib/ && cp pnglibconf.h ../png.h ../pngconf.h ~/sw/include/
|
||||||
|
|
||||||
|
freetype
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Get the .zip source from: http://download.savannah.gnu.org/releases/freetype/
|
||||||
|
|
||||||
|
Edit *all copies* of the file ftoption.h and add to generate a .lib
|
||||||
|
and a correct dll
|
||||||
|
|
||||||
|
#define FT_EXPORT(return_type) __declspec(dllexport) return_type
|
||||||
|
#define FT_EXPORT_DEF(return_type) __declspec(dllexport) return_type
|
||||||
|
|
||||||
|
VS 2008 .sln file is present, open it
|
||||||
|
|
||||||
|
* If you are doing x64 build, click the Win32 dropdown, select
|
||||||
|
Configuration manager->Active solution platform -> New -> x64
|
||||||
|
|
||||||
|
* Change active build type to release multithreaded
|
||||||
|
|
||||||
|
* Project->Properties->Configuration Properties change configuration type
|
||||||
|
to dll and build solution
|
||||||
|
|
||||||
|
cp "`find . -name freetype.dll`" ~/sw/bin/ && cp "`find . -name freetype.lib`" ~/sw/lib/
|
||||||
|
|
||||||
|
Now change configuration back to static for .lib and build solution
|
||||||
|
|
||||||
|
cp "`find . -name 'freetype*MT.lib'`" ~/sw/lib/
|
||||||
|
cp -rf include ~/sw/include/freetype2 && rm -rf ~/sw/include/freetype2/internal
|
||||||
|
|
||||||
|
TODO: Test if this bloody thing actually works on 64 bit (apparently freetype
|
||||||
|
assumes sizeof(long) == sizeof(ptr) which is not true in Win64. See for
|
||||||
|
example: http://forum.openscenegraph.org/viewtopic.php?t=2880
|
||||||
|
|
||||||
|
expat
|
||||||
|
--------
|
||||||
|
|
||||||
|
Get from: http://sourceforge.net/projects/expat/files/expat/
|
||||||
|
|
||||||
|
Apparently expat requires stdint.h which VS 2008 does not have. So we get our
|
||||||
|
own.
|
||||||
|
|
||||||
|
Run::
|
||||||
|
cd lib && wget http://msinttypes.googlecode.com/svn/trunk/stdint.h && cd ..
|
||||||
|
mkdir -p build && cd build
|
||||||
|
cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
nmake
|
||||||
|
cp expat.dll ~/sw/bin/ && cp expat.lib ~/sw/lib/
|
||||||
|
cp ../lib/expat.h ../lib/expat_external.h ~/sw/include
|
||||||
|
|
||||||
|
libiconv
|
||||||
|
----------
|
||||||
|
|
||||||
|
Run::
|
||||||
|
mkdir vs2008 && cd vs2008
|
||||||
|
|
||||||
|
Then follow these instructions:
|
||||||
|
http://www.codeproject.com/Articles/302012/How-to-Build-libiconv-with-Microsoft-Visual-Studio
|
||||||
|
|
||||||
|
NOTE: Built as MT rather than MD so no manifest
|
||||||
|
|
||||||
|
Change the type to Release and config to x64 or Win32 and Build solution and
|
||||||
|
then::
|
||||||
|
cp "`find . -name '*.dll'`" ~/sw/bin/
|
||||||
|
cp "`find . -name '*.lib'`" ~/sw/lib/iconv.lib
|
||||||
|
cp "`find . -name iconv.h`" ~/sw/include/
|
||||||
|
|
||||||
|
Information for using a static version of libiconv is at the link above.
|
||||||
|
|
||||||
|
libxml2
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Get it from: ftp://xmlsoft.org/libxml2/
|
||||||
|
|
||||||
|
Run::
|
||||||
|
cd win32
|
||||||
|
cscript.exe configure.js include=C:/cygwin64/home/kovid/sw/include lib=C:/cygwin64/home/kovid/sw/lib prefix=C:/cygwin64/home/kovid/sw zlib=yes iconv=yes
|
||||||
|
nmake /f Makefile.msvc
|
||||||
|
cd ..
|
||||||
|
mkdir -p ~/sw/include/libxml2/libxml && cp include/libxml/*.h ~/sw/include/libxml2/libxml/
|
||||||
|
find . -type f \( -name "*.dll" -o -name "*.dll.manifest" \) -exec cp "{}" ~/sw/bin/ \;
|
||||||
|
find . -name libxml2.lib -exec cp "{}" ~/sw/lib/ \;
|
||||||
|
|
||||||
|
libxslt
|
||||||
|
---------
|
||||||
|
|
||||||
|
Get it from: ftp://xmlsoft.org/libxml2/
|
||||||
|
|
||||||
|
Run::
|
||||||
|
cd win32
|
||||||
|
cscript.exe configure.js include=C:/cygwin64/home/kovid/sw/include include=C:/cygwin64/home/kovid/sw/include/libxml2 lib=C:/cygwin64/home/kovid/sw/lib prefix=C:/cygwin64/home/kovid/sw zlib=yes iconv=yes
|
||||||
|
nmake /f Makefile.msvc
|
||||||
|
mkdir -p ~/sw/include/libxslt ~/sw/include/libexslt
|
||||||
|
cd ..
|
||||||
|
cp libxslt/*.h ~/sw/include/libxslt/
|
||||||
|
cp libexslt/*.h ~/sw/include/libexslt/
|
||||||
|
find . -type f \( -name "*.dll" -o -name "*.dll.manifest" \) -exec cp "{}" ~/sw/bin/ \;
|
||||||
|
find . -name 'lib*xslt.lib' -exec cp "{}" ~/sw/lib/ \;
|
||||||
|
|
||||||
|
lxml
|
||||||
|
------
|
||||||
|
|
||||||
|
Get the source from: http://pypi.python.org/pypi/lxml
|
||||||
|
|
||||||
|
Change the include dirs and lib dirs by editing setupinfo.py and changing the
|
||||||
|
library_dirs() function to return::
|
||||||
|
|
||||||
|
return ['C:/cygwin64/home/kovid/sw/lib']
|
||||||
|
|
||||||
|
and the include_dirs() function to return
|
||||||
|
|
||||||
|
return ['C:/cygwin64/home/kovid/sw/include/libxml2', 'C:/cygwin64/home/kovid/sw/include']
|
||||||
|
|
||||||
|
Run::
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
|
||||||
|
Python Imaging Library
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Download from http://pypi.python.org/pypi/Pillow/
|
||||||
|
Edit setup.py setting the ROOT values, like this::
|
||||||
|
|
||||||
|
SW = r'C:\cygwin64\home\kovid\sw'
|
||||||
|
JPEG_ROOT = ZLIB_ROOT = FREETYPE_ROOT = (SW+r'\lib', SW+r'\include')
|
||||||
|
|
||||||
|
Set zip_safe=False
|
||||||
|
|
||||||
|
Build and install with::
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
poppler
|
||||||
|
-------------
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
|
||||||
|
Run the cmake GUI which will find the various dependencies automatically.
|
||||||
|
On 64 bit cmake might not let you choose Visual Studio 2008, in whcih case
|
||||||
|
leave the source field blank, click configure choose Visual Studio 2008 and
|
||||||
|
then enter the source field.
|
||||||
|
|
||||||
|
In cmake: disable GTK, Qt, openjpeg, cpp, lcms, gtk_tests, qt_tests. Enable
|
||||||
|
jpeg, png and zlib::
|
||||||
|
|
||||||
|
cp build/utils/Release/*.exe ~/sw/bin
|
||||||
|
|
||||||
|
podofo
|
||||||
|
----------
|
||||||
|
|
||||||
|
Download from http://podofo.sourceforge.net/download.html
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
|
||||||
|
Add the following three lines near the top of CMakeLists.txt
|
||||||
|
SET(WANT_LIB64 FALSE)
|
||||||
|
SET(PODOFO_BUILD_SHARED TRUE)
|
||||||
|
SET(PODOFO_BUILD_STATIC FALSE)
|
||||||
|
|
||||||
|
PoDoFo's CMakeLists.txt is pretty bad. Run the cmake-gui and fill in values for
|
||||||
|
freetype2 and open ssl (choose any one .lib for the libcrypto variable, you
|
||||||
|
will have to fix it manually in Visual Studio later anyway). Then generate the
|
||||||
|
VisualStudio solution. In the solution. In the Solution got to
|
||||||
|
Project->Properties->Linker->Input and add the second ssl library. And in
|
||||||
|
C++->General add the openssl include dir.
|
||||||
|
|
||||||
|
Now build only the project podofo_shared (release mode)
|
||||||
|
|
||||||
|
Run::
|
||||||
|
cp "`find . -name '*.dll'`" ~/sw/bin/
|
||||||
|
cp "`find . -name '*.lib'`" ~/sw/lib/
|
||||||
|
mkdir ~/sw/include/podofo
|
||||||
|
cp build/podofo_config.h ~/sw/include/podofo
|
||||||
|
cp -r src/* ~/sw/include/podofo/
|
||||||
|
|
||||||
|
|
||||||
|
ImageMagick
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Get the source from: http://www.imagemagick.org/download/windows/ImageMagick-windows.zip
|
||||||
|
Unzip it and then run::
|
||||||
|
chmod +x `find . -name '*.exe'`
|
||||||
|
|
||||||
|
Edit VisualMagick/configure/configure.cpp to set
|
||||||
|
|
||||||
|
int projectType = MULTITHREADEDDLL;
|
||||||
|
|
||||||
|
Open configure.sln and build it to create configure.exe
|
||||||
|
|
||||||
|
Run configure.exe set 32/64 bit disable X11 and OpenMPI and click the Edit
|
||||||
|
magick-baseconfig.h button
|
||||||
|
|
||||||
|
Undefine ProvideDllMain
|
||||||
|
|
||||||
|
Now open VisualMagick/VisualDynamicMT.sln set to Release
|
||||||
|
|
||||||
|
Remove the UTIL_IMdisplay and CORE_Magick++ projects.
|
||||||
|
|
||||||
|
F7 for build solution.
|
||||||
|
|
||||||
|
netifaces
|
||||||
|
------------
|
||||||
|
|
||||||
|
Download the source tarball from http://alastairs-place.net/projects/netifaces/
|
||||||
|
|
||||||
|
Rename netifaces.c to netifaces.cpp and make the same change in setup.py
|
||||||
|
|
||||||
|
Run::
|
||||||
|
python setup.py build
|
||||||
|
cp `find build/ -name *.pyd` /cygdrive/c/Python27/Lib/site-packages/
|
||||||
|
|
||||||
|
|
||||||
|
psutil
|
||||||
|
--------
|
||||||
|
|
||||||
|
Download the source tarball
|
||||||
|
|
||||||
|
Run
|
||||||
|
|
||||||
|
Python setup.py build
|
||||||
|
cp -r build/lib.win32-*/* /cygdrive/c/Python27/Lib/site-packages/
|
||||||
|
|
||||||
|
easylzma
|
||||||
|
----------
|
||||||
|
|
||||||
|
This is only needed to build the portable installer.
|
||||||
|
|
||||||
|
Get it from http://lloyd.github.com/easylzma/ (use the trunk version)
|
||||||
|
|
||||||
|
Run cmake and build the Visual Studio solution (generates CLI tools and dll and
|
||||||
|
static lib automatically)
|
||||||
|
|
||||||
|
chmlib
|
||||||
|
-------
|
||||||
|
|
||||||
|
Download the zip source code from: http://www.jedrea.com/chmlib/
|
||||||
|
Run::
|
||||||
|
cd src && unzip ./ChmLib-ds6.zip
|
||||||
|
Then open ChmLib.dsw in Visual Studio, change the configuration to Release
|
||||||
|
(Win32|x64) and build solution, this will generate a static library in
|
||||||
|
Release/ChmLib.lib
|
||||||
|
|
||||||
Qt
|
Qt
|
||||||
--------
|
--------
|
||||||
Download Qt sourcecode (.zip) from: http://download.qt-project.org/official_releases/qt/
|
Download Qt sourcecode (.zip) from: http://download.qt-project.org/official_releases/qt/
|
||||||
@ -225,328 +520,6 @@ Compiling instructions::
|
|||||||
nmake
|
nmake
|
||||||
nmake install
|
nmake install
|
||||||
|
|
||||||
ICU
|
|
||||||
-------
|
|
||||||
|
|
||||||
Download the win32 source .zip from http://www.icu-project.org/download
|
|
||||||
|
|
||||||
Extract to q:\icu
|
|
||||||
|
|
||||||
Add Q:\icu\bin to PATH and reboot
|
|
||||||
|
|
||||||
In a Visual Studio Command Prompt
|
|
||||||
cd to <ICU>\source
|
|
||||||
Run set PATH=%PATH%;c:\cygwin\bin
|
|
||||||
Run dos2unix on configure and runConfigureICU
|
|
||||||
|
|
||||||
Run bash ./runConfigureICU Cygwin/MSVC
|
|
||||||
|
|
||||||
Run make (note that you must have GNU make installed in cygwin)
|
|
||||||
|
|
||||||
Optionally run make check
|
|
||||||
|
|
||||||
zlib
|
|
||||||
------
|
|
||||||
|
|
||||||
Build with::
|
|
||||||
nmake -f win32/Makefile.msc
|
|
||||||
nmake -f win32/Makefile.msc test
|
|
||||||
|
|
||||||
cp zlib1.dll* ../../bin
|
|
||||||
cp zlib.lib zdll.* ../../lib
|
|
||||||
cp zconf.h zlib.h ../../include
|
|
||||||
|
|
||||||
jpeg-8
|
|
||||||
-------
|
|
||||||
|
|
||||||
Get the source code from: http://sourceforge.net/projects/libjpeg-turbo/files/
|
|
||||||
|
|
||||||
Run::
|
|
||||||
chmod +x cmakescripts/* && cd build
|
|
||||||
cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DWITH_JPEG8=1 ..
|
|
||||||
nmake
|
|
||||||
cp sharedlib/jpeg8.dll* ~/sw/bin/
|
|
||||||
cp sharedlib/jpeg.lib ~/sw/lib/
|
|
||||||
cp jconfig.h ../jerror.h ../jpeglib.h ../jmorecfg.h ~/sw/include
|
|
||||||
|
|
||||||
libpng
|
|
||||||
---------
|
|
||||||
|
|
||||||
Download the libpng .zip source file from:
|
|
||||||
http://www.libpng.org/pub/png/libpng.html
|
|
||||||
|
|
||||||
Run::
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DZLIB_INCLUDE_DIR=C:/cygwin/home/kovid/sw/include -DZLIB_LIBRARY=C:/cygwin/home/kovid/sw/lib/zdll.lib ..
|
|
||||||
nmake
|
|
||||||
cp libpng*.dll ~/sw/bin/
|
|
||||||
cp libpng*.lib ~/sw/lib/
|
|
||||||
cp pnglibconf.h ../png.h ../pngconf.h ~/sw/include/
|
|
||||||
|
|
||||||
freetype
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Get the .zip source from: http://download.savannah.gnu.org/releases/freetype/
|
|
||||||
|
|
||||||
Edit *all copies* of the file ftoption.h and add to generate a .lib
|
|
||||||
and a correct dll
|
|
||||||
|
|
||||||
#define FT_EXPORT(return_type) __declspec(dllexport) return_type
|
|
||||||
#define FT_EXPORT_DEF(return_type) __declspec(dllexport) return_type
|
|
||||||
|
|
||||||
|
|
||||||
VS 2008 .sln file is present, open it
|
|
||||||
|
|
||||||
* If you are doing x64 build, click the Win32 dropdown, select
|
|
||||||
Configuration manager->Active solution platform -> New -> x64
|
|
||||||
|
|
||||||
* Change active build type to release mutithreaded
|
|
||||||
|
|
||||||
* Project->Properties->Configuration Properties change configuration type
|
|
||||||
to dll and build solution
|
|
||||||
|
|
||||||
cp "`find . -name *.dll`" ~/sw/bin/
|
|
||||||
cp "`find . -name freetype.lib`" ~/sw/lib/
|
|
||||||
|
|
||||||
Now change configuration back to static for .lib and build solution
|
|
||||||
cp "`find . -name freetype*MT.lib`" ~/sw/lib/
|
|
||||||
|
|
||||||
cp build/freetype-2.3.9/objs/win32/vc2008/freetype239MT.lib lib/
|
|
||||||
cp -rf include/* ~/sw/include/
|
|
||||||
|
|
||||||
TODO: Test if this bloody thing actually works on 64 bit (apparently freetype
|
|
||||||
assumes sizeof(long) == sizeof(ptr) which is not true in Win64. See for
|
|
||||||
example: http://forum.openscenegraph.org/viewtopic.php?t=2880
|
|
||||||
|
|
||||||
expat
|
|
||||||
--------
|
|
||||||
|
|
||||||
Get from: http://sourceforge.net/projects/expat/files/expat/
|
|
||||||
|
|
||||||
Apparently expat requires stdint.h which VS 2008 does not have. So we get our
|
|
||||||
own.
|
|
||||||
|
|
||||||
Run::
|
|
||||||
cd lib
|
|
||||||
wget http://msinttypes.googlecode.com/svn/trunk/stdint.h
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..
|
|
||||||
nmake
|
|
||||||
cp expat.dll ~/sw/bin/ && cp expat.lib ~/sw/lib/
|
|
||||||
cp ../lib/expat.h ../lib/expat_external.h ~/sw/include
|
|
||||||
|
|
||||||
libiconv
|
|
||||||
----------
|
|
||||||
|
|
||||||
Run::
|
|
||||||
mkdir vs2008 && cd vs2008
|
|
||||||
|
|
||||||
Then follow these instructions:
|
|
||||||
http://www.codeproject.com/Articles/302012/How-to-Build-libiconv-with-Microsoft-Visual-Studio
|
|
||||||
|
|
||||||
Change the type to Release and config to x64 or Win32 and Build solution and
|
|
||||||
then::
|
|
||||||
cp "`find . -name *.dll`" ~/sw/bin/
|
|
||||||
cp "`find . -name *.dll.manifest`" ~/sw/bin/
|
|
||||||
cp "`find . -name *.lib`" ~/sw/lib/iconv.lib
|
|
||||||
cp "`find . -name iconv.h`" ~/sw/include/
|
|
||||||
|
|
||||||
Information for using a static version of libiconv is at the link above.
|
|
||||||
|
|
||||||
libxml2
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Get it from: ftp://xmlsoft.org/libxml2/
|
|
||||||
|
|
||||||
Run::
|
|
||||||
cd win32
|
|
||||||
cscript.exe configure.js include=C:/cygwin/home/kovid/sw/include lib=C:/cygwin/home/kovid/sw/lib prefix=C:/cygwin/home/kovid/sw zlib=yes iconv=yes
|
|
||||||
nmake /f Makefile.msvc
|
|
||||||
mkdir -p ~/sw/include/libxml2/libxml
|
|
||||||
cp include/libxml/*.h ~/sw/include/libxml2/libxml/
|
|
||||||
find . -type f \( -name "*.dll" -o -name "*.dll.manifest" \) -exec cp "{}" ~/sw/bin/ \;
|
|
||||||
find . -name libxml2.lib -exec cp "{}" ~/sw/lib/ \;
|
|
||||||
|
|
||||||
libxslt
|
|
||||||
---------
|
|
||||||
|
|
||||||
Get it from: ftp://xmlsoft.org/libxml2/
|
|
||||||
|
|
||||||
Run::
|
|
||||||
cd win32
|
|
||||||
cscript.exe configure.js include=C:/cygwin/home/kovid/sw/include include=C:/cygwin/home/kovid/sw/include/libxml2 lib=C:/cygwin/home/kovid/sw/lib prefix=C:/cygwin/home/kovid/sw zlib=yes iconv=yes
|
|
||||||
nmake /f Makefile.msvc
|
|
||||||
mkdir -p ~/sw/include/libxslt ~/sw/include/libexslt
|
|
||||||
cp libxslt/*.h ~/sw/include/libxslt/
|
|
||||||
cp libexslt/*.h ~/sw/include/libexslt/
|
|
||||||
find . -type f \( -name "*.dll" -o -name "*.dll.manifest" \) -exec cp "{}" ~/sw/bin/ \;
|
|
||||||
find . -name lib*xslt.lib -exec cp "{}" ~/sw/lib/ \;
|
|
||||||
|
|
||||||
lxml
|
|
||||||
------
|
|
||||||
|
|
||||||
Get the source from: http://pypi.python.org/pypi/lxml
|
|
||||||
|
|
||||||
Change the include dirs and lib dirs by editing setupinfo.py and changing the
|
|
||||||
library_dirs() function to return::
|
|
||||||
|
|
||||||
return ['C:/cygwin/home/kovid/sw/lib']
|
|
||||||
|
|
||||||
and the include_dirs() function to return
|
|
||||||
|
|
||||||
return ['C:/cygwin/home/kovid/sw/include/libxml2', 'C:/cygwin/home/kovid/sw/include']
|
|
||||||
|
|
||||||
Run::
|
|
||||||
python setup.py install
|
|
||||||
|
|
||||||
Python Imaging Library
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
For 32-bit:
|
|
||||||
Install as normal using installer at http://www.lfd.uci.edu/~gohlke/pythonlibs/
|
|
||||||
|
|
||||||
For 64-bit:
|
|
||||||
Download from http://pypi.python.org/pypi/Pillow/
|
|
||||||
Edit setup.py setting the ROOT values, like this::
|
|
||||||
|
|
||||||
SW = r'C:\cygwin\home\kovid\sw'
|
|
||||||
JPEG_ROOT = ZLIB_ROOT = FREETYPE_ROOT = (SW+r'\lib', SW+r'\include')
|
|
||||||
|
|
||||||
Build and install with::
|
|
||||||
python setup.py build
|
|
||||||
python setup.py install
|
|
||||||
|
|
||||||
Note that the lcms module will not be built. PIL requires lcms-1.x but only
|
|
||||||
lcms-2.x can be compiled as a 64 bit library.
|
|
||||||
|
|
||||||
Pillow >= 2.2 installs itself as a .egg file. calibre needs it to be a PIL
|
|
||||||
directory. Extract the PIL directory as follows:
|
|
||||||
cd /cygdrive/c/Python27/Lib/site-packages
|
|
||||||
mkdir p && cd p
|
|
||||||
unzip ../Pillow-*.egg
|
|
||||||
cd .. && rm Pillow-*.egg && mv p/PIL . && chmod +x PIL/*.pyd
|
|
||||||
|
|
||||||
Test it on the target system with
|
|
||||||
|
|
||||||
calibre-debug -c "from PIL import Image; import _imaging, _imagingmath, _imagingft"
|
|
||||||
|
|
||||||
kdewin32-msvc
|
|
||||||
----------------
|
|
||||||
|
|
||||||
I dont think this is needed any more, I've left it here just in case I'm wrong.
|
|
||||||
|
|
||||||
Get it from http://www.winkde.org/pub/kde/ports/win32/repository/kdesupport/
|
|
||||||
mkdir build
|
|
||||||
Run cmake
|
|
||||||
|
|
||||||
Set build type to release and configuration to dll
|
|
||||||
|
|
||||||
Build
|
|
||||||
|
|
||||||
cp build/kdewin32-msvc-0.3.9/build/include/* include/
|
|
||||||
cp build/kdewin32-msvc-0.3.9/build/bin/Release/*.dll bin/
|
|
||||||
cp build/kdewin32-msvc-0.3.9/build/bin/Release/*.lib lib/
|
|
||||||
cp build/kdewin32-msvc-0.3.9/build/bin/Release/*.exp lib/
|
|
||||||
cp -r build/kdewin32-msvc-0.3.9/include/msvc/ include/
|
|
||||||
cp build/kdewin32-msvc-0.3.9/include/*.h include/
|
|
||||||
|
|
||||||
poppler
|
|
||||||
-------------
|
|
||||||
|
|
||||||
mkdir build
|
|
||||||
|
|
||||||
Run the cmake GUI which will find the various dependencies automatically.
|
|
||||||
On 64 bit cmake might not let you choose Visual Studio 2008, in whcih case
|
|
||||||
leave the source field blank, click configure choose Visual Studio 2008 and
|
|
||||||
then enter the source field.
|
|
||||||
|
|
||||||
In Cmake: disable GTK, Qt, OPenjpeg, cpp, lcms, gtk_tests, qt_tests. Enable
|
|
||||||
jpeg, png and zlib::
|
|
||||||
|
|
||||||
cp build/utils/Release/*.exe ../../bin/
|
|
||||||
|
|
||||||
podofo
|
|
||||||
----------
|
|
||||||
|
|
||||||
Download from http://podofo.sourceforge.net/download.html
|
|
||||||
|
|
||||||
Add the following three lines near the top of CMakeLists.txt
|
|
||||||
SET(WANT_LIB64 FALSE)
|
|
||||||
SET(PODOFO_BUILD_SHARED TRUE)
|
|
||||||
SET(PODOFO_BUILD_STATIC FALSE)
|
|
||||||
|
|
||||||
Run::
|
|
||||||
cp "`find . -name *.dll`" ~/sw/bin/
|
|
||||||
cp "`find . -name *.lib`" ~/sw/lib/
|
|
||||||
mkdir ~/sw/include/podofo
|
|
||||||
cp build/podofo_config.h ~/sw/include/podofo
|
|
||||||
cp -r src/* ~/sw/include/podofo/
|
|
||||||
|
|
||||||
|
|
||||||
ImageMagick
|
|
||||||
--------------
|
|
||||||
|
|
||||||
Get the source from: http://www.imagemagick.org/download/windows/ImageMagick-windows.zip
|
|
||||||
|
|
||||||
Edit VisualMagick/configure/configure.cpp to set
|
|
||||||
|
|
||||||
int projectType = MULTITHREADEDDLL;
|
|
||||||
|
|
||||||
Run configure.bat in a visual studio command prompt
|
|
||||||
|
|
||||||
Run configure.exe generated by configure.bat
|
|
||||||
|
|
||||||
Edit magick/magick-config.h
|
|
||||||
|
|
||||||
Undefine ProvideDllMain and MAGICKCORE_X11_DELEGATE
|
|
||||||
|
|
||||||
Now open VisualMagick/VisualDynamicMT.sln set to Release
|
|
||||||
Remove the CORE_xlib, UTIL_Imdisplay and CORE_Magick++ projects.
|
|
||||||
|
|
||||||
F7 for build solution, you will get one error due to the removal of xlib, ignore
|
|
||||||
it.
|
|
||||||
|
|
||||||
netifaces
|
|
||||||
------------
|
|
||||||
|
|
||||||
Download the source tarball from http://alastairs-place.net/projects/netifaces/
|
|
||||||
|
|
||||||
Rename netifaces.c to netifaces.cpp and make the same change in setup.py
|
|
||||||
|
|
||||||
Run::
|
|
||||||
python setup.py build
|
|
||||||
cp `find build/ -name *.pyd` /cygdrive/c/Python27/Lib/site-packages/
|
|
||||||
|
|
||||||
|
|
||||||
psutil
|
|
||||||
--------
|
|
||||||
|
|
||||||
Download the source tarball
|
|
||||||
|
|
||||||
Run
|
|
||||||
|
|
||||||
Python setup.py build
|
|
||||||
cp -r build/lib.win32-*/* /cygdrive/c/Python27/Lib/site-packages/
|
|
||||||
|
|
||||||
easylzma
|
|
||||||
----------
|
|
||||||
|
|
||||||
This is only needed to build the portable installer.
|
|
||||||
|
|
||||||
Get it from http://lloyd.github.com/easylzma/ (use the trunk version)
|
|
||||||
|
|
||||||
Run cmake and build the Visual Studio solution (generates CLI tools and dll and
|
|
||||||
static lib automatically)
|
|
||||||
|
|
||||||
chmlib
|
|
||||||
-------
|
|
||||||
|
|
||||||
Download the zip source code from: http://www.jedrea.com/chmlib/
|
|
||||||
Run::
|
|
||||||
cd src && unzip ./ChmLib-ds6.zip
|
|
||||||
Then open ChmLib.dsw in Visual Studio, change the configuration to Release
|
|
||||||
(Win32|x64) and build solution, this will generate a static library in
|
|
||||||
Release/ChmLib.lib
|
|
||||||
|
|
||||||
libimobiledevice
|
libimobiledevice
|
||||||
------------------
|
------------------
|
||||||
|
@ -21,7 +21,7 @@ class InvalidPlugin(ValueError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Plugin(object): # {{{
|
class Plugin(object): # {{{
|
||||||
'''
|
'''
|
||||||
A calibre plugin. Useful members include:
|
A calibre plugin. Useful members include:
|
||||||
|
|
||||||
@ -225,7 +225,6 @@ class Plugin(object): # {{{
|
|||||||
ans[candidate] = zf.read(candidate)
|
ans[candidate] = zf.read(candidate)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def customization_help(self, gui=False):
|
def customization_help(self, gui=False):
|
||||||
'''
|
'''
|
||||||
Return a string giving help on how to customize this plugin.
|
Return a string giving help on how to customize this plugin.
|
||||||
@ -284,7 +283,6 @@ class Plugin(object): # {{{
|
|||||||
sys.path.insert(0, self.sys_insertion_path)
|
sys.path.insert(0, self.sys_insertion_path)
|
||||||
zf.close()
|
zf.close()
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
ip, it = getattr(self, 'sys_insertion_path', None), getattr(self,
|
ip, it = getattr(self, 'sys_insertion_path', None), getattr(self,
|
||||||
'_sys_insertion_tdir', None)
|
'_sys_insertion_tdir', None)
|
||||||
@ -304,7 +302,7 @@ class Plugin(object): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class FileTypePlugin(Plugin): # {{{
|
class FileTypePlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that is associated with a particular set of file types.
|
A plugin that is associated with a particular set of file types.
|
||||||
'''
|
'''
|
||||||
@ -356,13 +354,13 @@ class FileTypePlugin(Plugin): # {{{
|
|||||||
|
|
||||||
:param book_id: Database id of the added book.
|
:param book_id: Database id of the added book.
|
||||||
:param book_format: The file type of the book that was added.
|
:param book_format: The file type of the book that was added.
|
||||||
:param db: Library database.
|
:param db: Library database.
|
||||||
'''
|
'''
|
||||||
pass # Default implementation does nothing
|
pass # Default implementation does nothing
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class MetadataReaderPlugin(Plugin): # {{{
|
class MetadataReaderPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements reading metadata from a set of file types.
|
A plugin that implements reading metadata from a set of file types.
|
||||||
'''
|
'''
|
||||||
@ -392,7 +390,7 @@ class MetadataReaderPlugin(Plugin): # {{{
|
|||||||
return None
|
return None
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class MetadataWriterPlugin(Plugin): # {{{
|
class MetadataWriterPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements reading metadata from a set of file types.
|
A plugin that implements reading metadata from a set of file types.
|
||||||
'''
|
'''
|
||||||
@ -423,7 +421,7 @@ class MetadataWriterPlugin(Plugin): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class CatalogPlugin(Plugin): # {{{
|
class CatalogPlugin(Plugin): # {{{
|
||||||
'''
|
'''
|
||||||
A plugin that implements a catalog generator.
|
A plugin that implements a catalog generator.
|
||||||
'''
|
'''
|
||||||
@ -516,8 +514,7 @@ class CatalogPlugin(Plugin): # {{{
|
|||||||
from calibre.customize.ui import config
|
from calibre.customize.ui import config
|
||||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||||
|
|
||||||
if not type(self) in builtin_plugins and \
|
if not type(self) in builtin_plugins and self.name not in config['disabled_plugins']:
|
||||||
not self.name in config['disabled_plugins']:
|
|
||||||
files_to_copy = ["%s.%s" % (self.name.lower(),ext) for ext in ["ui","py"]]
|
files_to_copy = ["%s.%s" % (self.name.lower(),ext) for ext in ["ui","py"]]
|
||||||
resources = zipfile.ZipFile(self.plugin_path,'r')
|
resources = zipfile.ZipFile(self.plugin_path,'r')
|
||||||
|
|
||||||
@ -553,7 +550,7 @@ class CatalogPlugin(Plugin): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class InterfaceActionBase(Plugin): # {{{
|
class InterfaceActionBase(Plugin): # {{{
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
author = 'Kovid Goyal'
|
author = 'Kovid Goyal'
|
||||||
@ -580,7 +577,7 @@ class InterfaceActionBase(Plugin): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class PreferencesPlugin(Plugin): # {{{
|
class PreferencesPlugin(Plugin): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
A plugin representing a widget displayed in the Preferences dialog.
|
A plugin representing a widget displayed in the Preferences dialog.
|
||||||
@ -639,7 +636,7 @@ class PreferencesPlugin(Plugin): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class StoreBase(Plugin): # {{{
|
class StoreBase(Plugin): # {{{
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
author = 'John Schember'
|
author = 'John Schember'
|
||||||
@ -688,7 +685,7 @@ class StoreBase(Plugin): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ViewerPlugin(Plugin): # {{{
|
class ViewerPlugin(Plugin): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
These plugins are used to add functionality to the calibre viewer.
|
These plugins are used to add functionality to the calibre viewer.
|
||||||
@ -733,6 +730,7 @@ class ViewerPlugin(Plugin): # {{{
|
|||||||
example, you can modify the toolbars via ui.tool_bar and ui.tool_bar2.
|
example, you can modify the toolbars via ui.tool_bar and ui.tool_bar2.
|
||||||
'''
|
'''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def customize_context_menu(self, menu, event, hit_test_result):
|
def customize_context_menu(self, menu, event, hit_test_result):
|
||||||
'''
|
'''
|
||||||
This method is called every time the context (right-click) menu is
|
This method is called every time the context (right-click) menu is
|
||||||
@ -743,4 +741,3 @@ class ViewerPlugin(Plugin): # {{{
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ from cssselect.xpath import XPathExpr, is_safe_name
|
|||||||
|
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XPNSMAP, XHTML_NS
|
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS, XPNSMAP, XHTML_NS
|
||||||
|
from calibre.ebooks.oeb.normalize_css import normalize_filter_css, normalizers
|
||||||
from calibre.ebooks.oeb.stylizer import MIN_SPACE_RE, is_non_whitespace, xpath_lower_case, fix_namespace
|
from calibre.ebooks.oeb.stylizer import MIN_SPACE_RE, is_non_whitespace, xpath_lower_case, fix_namespace
|
||||||
from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style
|
from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style
|
||||||
|
|
||||||
@ -167,3 +168,80 @@ def remove_unused_css(container, report):
|
|||||||
else:
|
else:
|
||||||
report(_('No unused CSS style rules found'))
|
report(_('No unused CSS style rules found'))
|
||||||
return num_of_removed_rules > 0
|
return num_of_removed_rules > 0
|
||||||
|
|
||||||
|
def filter_declaration(style, properties):
|
||||||
|
changed = False
|
||||||
|
for prop in properties:
|
||||||
|
if style.removeProperty(prop) != '':
|
||||||
|
changed = True
|
||||||
|
all_props = set(style.keys())
|
||||||
|
for prop in style.getProperties():
|
||||||
|
n = normalizers.get(prop.name, None)
|
||||||
|
if n is not None:
|
||||||
|
normalized = n(prop.name, prop.propertyValue)
|
||||||
|
removed = properties.intersection(set(normalized))
|
||||||
|
if removed:
|
||||||
|
changed = True
|
||||||
|
style.removeProperty(prop.name)
|
||||||
|
for prop in set(normalized) - removed - all_props:
|
||||||
|
style.setProperty(prop, normalized[prop])
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def filter_sheet(sheet, properties):
|
||||||
|
from cssutils.css import CSSRule
|
||||||
|
changed = False
|
||||||
|
remove = []
|
||||||
|
for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
||||||
|
if filter_declaration(rule.style, properties):
|
||||||
|
changed = True
|
||||||
|
if rule.style.length == 0:
|
||||||
|
remove.append(rule)
|
||||||
|
for rule in remove:
|
||||||
|
sheet.cssRules.remove(rule)
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def filter_css(container, properties, names=()):
|
||||||
|
if not names:
|
||||||
|
types = OEB_STYLES | OEB_DOCS
|
||||||
|
names = []
|
||||||
|
for name, mt in container.mime_map.iteritems():
|
||||||
|
if mt in types:
|
||||||
|
names.append(name)
|
||||||
|
properties = normalize_filter_css(properties)
|
||||||
|
doc_changed = False
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
mt = container.mime_map[name]
|
||||||
|
if mt in OEB_STYLES:
|
||||||
|
sheet = container.parsed(name)
|
||||||
|
filtered = filter_sheet(sheet, properties)
|
||||||
|
if filtered:
|
||||||
|
container.dirty(name)
|
||||||
|
doc_changed = True
|
||||||
|
elif mt in OEB_DOCS:
|
||||||
|
root = container.parsed(name)
|
||||||
|
changed = False
|
||||||
|
for style in root.xpath('//*[local-name()="style"]'):
|
||||||
|
if style.text and style.get('type', 'text/css') in {None, '', 'text/css'}:
|
||||||
|
sheet = container.parse_css(style.text)
|
||||||
|
if filter_sheet(sheet, properties):
|
||||||
|
changed = True
|
||||||
|
style.text = force_unicode(sheet.cssText, 'utf-8')
|
||||||
|
pretty_script_or_style(container, style)
|
||||||
|
for elem in root.xpath('//*[@style]'):
|
||||||
|
text = elem.get('style', None)
|
||||||
|
if text:
|
||||||
|
style = container.parse_css(text, is_declaration=True)
|
||||||
|
if filter_declaration(style, properties):
|
||||||
|
changed = True
|
||||||
|
if style.length == 0:
|
||||||
|
del elem.attrib['style']
|
||||||
|
else:
|
||||||
|
elem.set('style', force_unicode(style.getCssText(separator=' '), 'utf-8'))
|
||||||
|
if changed:
|
||||||
|
container.dirty(name)
|
||||||
|
doc_changed = True
|
||||||
|
|
||||||
|
return doc_changed
|
||||||
|
|
||||||
|
@ -128,11 +128,17 @@ def read_words_from_html_tag(tag, words, file_name, parent_locale, locale):
|
|||||||
|
|
||||||
def locale_from_tag(tag):
|
def locale_from_tag(tag):
|
||||||
if 'lang' in tag.attrib:
|
if 'lang' in tag.attrib:
|
||||||
loc = parse_lang_code(tag.get('lang'))
|
try:
|
||||||
|
loc = parse_lang_code(tag.get('lang'))
|
||||||
|
except ValueError:
|
||||||
|
loc = None
|
||||||
if loc is not None:
|
if loc is not None:
|
||||||
return loc
|
return loc
|
||||||
if '{http://www.w3.org/XML/1998/namespace}lang' in tag.attrib:
|
if '{http://www.w3.org/XML/1998/namespace}lang' in tag.attrib:
|
||||||
loc = parse_lang_code(tag.get('{http://www.w3.org/XML/1998/namespace}lang'))
|
try:
|
||||||
|
loc = parse_lang_code(tag.get('{http://www.w3.org/XML/1998/namespace}lang'))
|
||||||
|
except ValueError:
|
||||||
|
loc = None
|
||||||
if loc is not None:
|
if loc is not None:
|
||||||
return loc
|
return loc
|
||||||
|
|
||||||
|
@ -253,6 +253,10 @@ class StatsCollector(object):
|
|||||||
src = rule.get('src', None)
|
src = rule.get('src', None)
|
||||||
if not src:
|
if not src:
|
||||||
continue
|
continue
|
||||||
|
if src.startswith('url(') and src.endswith(')') and src[4] not in {'"', "'"}:
|
||||||
|
# Quote the url otherwise cssutils fails to parse it if it has
|
||||||
|
# ' or " in it
|
||||||
|
src = "url('" + src[4:-1].replace("'", "\\'") + "')"
|
||||||
style = self.parser.parseStyle('background-image:%s'%src, validate=False)
|
style = self.parser.parseStyle('background-image:%s'%src, validate=False)
|
||||||
src = style.getProperty('background-image').propertyValue[0].uri
|
src = style.getProperty('background-image').propertyValue[0].uri
|
||||||
name = self.href_to_name(src, '@font-face rule')
|
name = self.href_to_name(src, '@font-face rule')
|
||||||
|
@ -432,7 +432,20 @@ class PolishAction(InterfaceAction):
|
|||||||
return None
|
return None
|
||||||
db = self.gui.library_view.model().db
|
db = self.gui.library_view.model().db
|
||||||
ans = (db.id(r) for r in rows)
|
ans = (db.id(r) for r in rows)
|
||||||
return self.get_supported_books(ans)
|
ans = self.get_supported_books(ans)
|
||||||
|
for fmts in ans.itervalues():
|
||||||
|
for x in fmts:
|
||||||
|
if x.startswith('ORIGINAL_'):
|
||||||
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
|
if not confirm(_(
|
||||||
|
'One of the books you are polishing has an {0} format.'
|
||||||
|
' Polishing will use this as the source and overwrite'
|
||||||
|
' any existing {1} format. Are you sure you want to proceed?').format(
|
||||||
|
x, x[len('ORIGINAL_'):]), 'confirm_original_polish', title=_('Are you sure?'),
|
||||||
|
confirm_msg=_('Ask for this confirmation again')):
|
||||||
|
return {}
|
||||||
|
break
|
||||||
|
return ans
|
||||||
|
|
||||||
def get_supported_books(self, book_ids):
|
def get_supported_books(self, book_ids):
|
||||||
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
||||||
|
@ -18,8 +18,9 @@ from calibre import prints, isbytestring
|
|||||||
from calibre.ptempfile import PersistentTemporaryDirectory, TemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory, TemporaryDirectory
|
||||||
from calibre.ebooks.oeb.base import urlnormalize
|
from calibre.ebooks.oeb.base import urlnormalize
|
||||||
from calibre.ebooks.oeb.polish.main import SUPPORTED, tweak_polish
|
from calibre.ebooks.oeb.polish.main import SUPPORTED, tweak_polish
|
||||||
from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, guess_type, OEB_FONTS
|
from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, guess_type, OEB_FONTS, OEB_DOCS, OEB_STYLES
|
||||||
from calibre.ebooks.oeb.polish.cover import mark_as_cover, mark_as_titlepage
|
from calibre.ebooks.oeb.polish.cover import mark_as_cover, mark_as_titlepage
|
||||||
|
from calibre.ebooks.oeb.polish.css import filter_css
|
||||||
from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all
|
from calibre.ebooks.oeb.polish.pretty import fix_all_html, pretty_all
|
||||||
from calibre.ebooks.oeb.polish.replace import rename_files, replace_file, get_recommended_folders, rationalize_folders
|
from calibre.ebooks.oeb.polish.replace import rename_files, replace_file, get_recommended_folders, rationalize_folders
|
||||||
from calibre.ebooks.oeb.polish.split import split, merge, AbortError, multisplit
|
from calibre.ebooks.oeb.polish.split import split, merge, AbortError, multisplit
|
||||||
@ -41,7 +42,7 @@ from calibre.gui2.tweak_book.search import validate_search_request, run_search
|
|||||||
from calibre.gui2.tweak_book.spell import find_next as find_next_word
|
from calibre.gui2.tweak_book.spell import find_next as find_next_word
|
||||||
from calibre.gui2.tweak_book.widgets import (
|
from calibre.gui2.tweak_book.widgets import (
|
||||||
RationalizeFolders, MultiSplit, ImportForeign, QuickOpen, InsertLink,
|
RationalizeFolders, MultiSplit, ImportForeign, QuickOpen, InsertLink,
|
||||||
InsertSemantics, BusyCursor, InsertTag)
|
InsertSemantics, BusyCursor, InsertTag, FilterCSS)
|
||||||
|
|
||||||
_diff_dialogs = []
|
_diff_dialogs = []
|
||||||
|
|
||||||
@ -674,6 +675,31 @@ class Boss(QObject):
|
|||||||
d.apply_changes(current_container())
|
d.apply_changes(current_container())
|
||||||
self.apply_container_update_to_gui()
|
self.apply_container_update_to_gui()
|
||||||
|
|
||||||
|
def filter_css(self):
|
||||||
|
self.commit_all_editors_to_container()
|
||||||
|
c = current_container()
|
||||||
|
ed = self.gui.central.current_editor
|
||||||
|
for name, q in editors.iteritems():
|
||||||
|
if ed is q:
|
||||||
|
current_name = name
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
current_name = None
|
||||||
|
if current_name and c.mime_map[current_name] not in OEB_DOCS | OEB_STYLES:
|
||||||
|
current_name = None
|
||||||
|
d = FilterCSS(current_name=current_name, parent=self.gui)
|
||||||
|
if d.exec_() == d.Accepted and d.filtered_properties:
|
||||||
|
self.add_savepoint(_('Before: Filter style information'))
|
||||||
|
with BusyCursor():
|
||||||
|
changed = filter_css(current_container(), d.filtered_properties, names=d.filter_names)
|
||||||
|
if changed:
|
||||||
|
self.apply_container_update_to_gui()
|
||||||
|
self.show_current_diff()
|
||||||
|
else:
|
||||||
|
self.rewind_savepoint()
|
||||||
|
return info_dialog(self.gui, _('No matches'), _(
|
||||||
|
'No matching style rules were found'), show=True)
|
||||||
|
|
||||||
def show_find(self):
|
def show_find(self):
|
||||||
self.gui.central.show_find()
|
self.gui.central.show_find()
|
||||||
ed = self.gui.central.current_editor
|
ed = self.gui.central.current_editor
|
||||||
|
@ -9,7 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt4.Qt import (
|
from PyQt4.Qt import (
|
||||||
QIcon, Qt, QSplitter, QListWidget, QTextBrowser, QPalette,
|
QIcon, Qt, QSplitter, QListWidget, QTextBrowser, QPalette, QMenu,
|
||||||
QListWidgetItem, pyqtSignal, QApplication, QStyledItemDelegate)
|
QListWidgetItem, pyqtSignal, QApplication, QStyledItemDelegate)
|
||||||
|
|
||||||
from calibre.ebooks.oeb.polish.check.base import WARN, INFO, DEBUG, ERROR, CRITICAL
|
from calibre.ebooks.oeb.polish.check.base import WARN, INFO, DEBUG, ERROR, CRITICAL
|
||||||
@ -28,6 +28,19 @@ def icon_for_level(level):
|
|||||||
icon = None
|
icon = None
|
||||||
return QIcon(I(icon)) if icon else QIcon()
|
return QIcon(I(icon)) if icon else QIcon()
|
||||||
|
|
||||||
|
def prefix_for_level(level):
|
||||||
|
if level > WARN:
|
||||||
|
text = _('ERROR')
|
||||||
|
elif level == WARN:
|
||||||
|
text = _('WARNING')
|
||||||
|
elif level == INFO:
|
||||||
|
text = _('INFO')
|
||||||
|
else:
|
||||||
|
text = ''
|
||||||
|
if text:
|
||||||
|
text += ': '
|
||||||
|
return text
|
||||||
|
|
||||||
class Delegate(QStyledItemDelegate):
|
class Delegate(QStyledItemDelegate):
|
||||||
|
|
||||||
def initStyleOption(self, option, index):
|
def initStyleOption(self, option, index):
|
||||||
@ -47,6 +60,8 @@ class Check(QSplitter):
|
|||||||
self.setChildrenCollapsible(False)
|
self.setChildrenCollapsible(False)
|
||||||
|
|
||||||
self.items = i = QListWidget(self)
|
self.items = i = QListWidget(self)
|
||||||
|
i.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
i.customContextMenuRequested.connect(self.context_menu)
|
||||||
self.items.setSpacing(3)
|
self.items.setSpacing(3)
|
||||||
self.items.itemDoubleClicked.connect(self.current_item_activated)
|
self.items.itemDoubleClicked.connect(self.current_item_activated)
|
||||||
self.items.currentItemChanged.connect(self.current_item_changed)
|
self.items.currentItemChanged.connect(self.current_item_changed)
|
||||||
@ -66,6 +81,22 @@ class Check(QSplitter):
|
|||||||
if state is not None:
|
if state is not None:
|
||||||
self.restoreState(state)
|
self.restoreState(state)
|
||||||
|
|
||||||
|
def context_menu(self, pos):
|
||||||
|
m = QMenu()
|
||||||
|
if self.items.count() > 0:
|
||||||
|
m.addAction(QIcon(I('edit-copy.png')), _('Copy list of errors to clipboard'), self.copy_to_clipboard)
|
||||||
|
if list(m.actions()):
|
||||||
|
m.exec_(self.mapToGlobal(pos))
|
||||||
|
|
||||||
|
def copy_to_clipboard(self):
|
||||||
|
items = []
|
||||||
|
for item in (self.items.item(i) for i in xrange(self.items.count())):
|
||||||
|
msg = unicode(item.text())
|
||||||
|
msg = prefix_for_level(item.data(Qt.UserRole).toPyObject().level) + msg
|
||||||
|
items.append(msg)
|
||||||
|
if items:
|
||||||
|
QApplication.clipboard().setText('\n'.join(items))
|
||||||
|
|
||||||
def save_state(self):
|
def save_state(self):
|
||||||
tprefs.set('check-book-splitter-state', bytearray(self.saveState()))
|
tprefs.set('check-book-splitter-state', bytearray(self.saveState()))
|
||||||
|
|
||||||
|
@ -349,6 +349,8 @@ class Main(MainWindow):
|
|||||||
_('Arrange into folders'))
|
_('Arrange into folders'))
|
||||||
self.action_set_semantics = reg('tags.png', _('Set &Semantics'), self.boss.set_semantics, 'set-semantics', (),
|
self.action_set_semantics = reg('tags.png', _('Set &Semantics'), self.boss.set_semantics, 'set-semantics', (),
|
||||||
_('Set Semantics'))
|
_('Set Semantics'))
|
||||||
|
self.action_filter_css = reg('filter.png', _('&Filter style information'), self.boss.filter_css, 'filter-css', (),
|
||||||
|
_('Filter style information'))
|
||||||
|
|
||||||
# Polish actions
|
# Polish actions
|
||||||
group = _('Polish Book')
|
group = _('Polish Book')
|
||||||
@ -482,6 +484,7 @@ class Main(MainWindow):
|
|||||||
e.addAction(self.action_pretty_all)
|
e.addAction(self.action_pretty_all)
|
||||||
e.addAction(self.action_rationalize_folders)
|
e.addAction(self.action_rationalize_folders)
|
||||||
e.addAction(self.action_set_semantics)
|
e.addAction(self.action_set_semantics)
|
||||||
|
e.addAction(self.action_filter_css)
|
||||||
e.addAction(self.action_spell_check_book)
|
e.addAction(self.action_spell_check_book)
|
||||||
e.addAction(self.action_check_book)
|
e.addAction(self.action_check_book)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ from PyQt4.Qt import (
|
|||||||
QFormLayout, QHBoxLayout, QToolButton, QIcon, QApplication, Qt, QWidget,
|
QFormLayout, QHBoxLayout, QToolButton, QIcon, QApplication, Qt, QWidget,
|
||||||
QPoint, QSizePolicy, QPainter, QStaticText, pyqtSignal, QTextOption,
|
QPoint, QSizePolicy, QPainter, QStaticText, pyqtSignal, QTextOption,
|
||||||
QAbstractListModel, QModelIndex, QVariant, QStyledItemDelegate, QStyle,
|
QAbstractListModel, QModelIndex, QVariant, QStyledItemDelegate, QStyle,
|
||||||
QListView, QTextDocument, QSize, QComboBox, QFrame, QCursor)
|
QListView, QTextDocument, QSize, QComboBox, QFrame, QCursor, QCheckBox)
|
||||||
|
|
||||||
from calibre import prepare_string_for_xml
|
from calibre import prepare_string_for_xml
|
||||||
from calibre.ebooks.oeb.polish.utils import lead_text
|
from calibre.ebooks.oeb.polish.utils import lead_text
|
||||||
@ -689,7 +689,7 @@ class InsertLink(Dialog):
|
|||||||
frag = item.get('id', None) or item.get('name')
|
frag = item.get('id', None) or item.get('name')
|
||||||
text = lead_text(item, num_words=4)
|
text = lead_text(item, num_words=4)
|
||||||
ac.append((text, frag))
|
ac.append((text, frag))
|
||||||
ac.sort(key=lambda (text, frag): primary_sort_key(text))
|
ac.sort(key=lambda text_frag: primary_sort_key(text_frag[0]))
|
||||||
self.anchor_names.model().set_names(self.anchor_cache[name])
|
self.anchor_names.model().set_names(self.anchor_cache[name])
|
||||||
self.update_target()
|
self.update_target()
|
||||||
|
|
||||||
@ -924,6 +924,75 @@ class InsertSemantics(Dialog):
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
class FilterCSS(Dialog): # {{{
|
||||||
|
|
||||||
|
def __init__(self, current_name=None, parent=None):
|
||||||
|
self.current_name = current_name
|
||||||
|
Dialog.__init__(self, _('Filter Style Information'), 'filter-css', parent=parent)
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
from calibre.gui2.convert.look_and_feel_ui import Ui_Form
|
||||||
|
f, w = Ui_Form(), QWidget()
|
||||||
|
f.setupUi(w)
|
||||||
|
self.l = l = QFormLayout(self)
|
||||||
|
self.setLayout(l)
|
||||||
|
|
||||||
|
l.addRow(QLabel(_('Select what style information you want completely removed:')))
|
||||||
|
self.h = h = QHBoxLayout()
|
||||||
|
|
||||||
|
for name, text in {
|
||||||
|
'fonts':_('&Fonts'), 'margins':_('&Margins'), 'padding':_('&Padding'), 'floats':_('Flo&ats'), 'colors':_('&Colors')}.iteritems():
|
||||||
|
c = QCheckBox(text)
|
||||||
|
setattr(self, 'opt_' + name, c)
|
||||||
|
h.addWidget(c)
|
||||||
|
c.setToolTip(getattr(f, 'filter_css_' + name).toolTip())
|
||||||
|
l.addRow(h)
|
||||||
|
|
||||||
|
self.others = o = QLineEdit(self)
|
||||||
|
l.addRow(_('&Other CSS properties:'), o)
|
||||||
|
o.setToolTip(f.filter_css_others.toolTip())
|
||||||
|
|
||||||
|
if self.current_name is not None:
|
||||||
|
self.filter_current = c = QCheckBox(_('Only filter CSS in the current file (%s)') % self.current_name)
|
||||||
|
l.addRow(c)
|
||||||
|
|
||||||
|
l.addRow(self.bb)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filter_names(self):
|
||||||
|
if self.current_name is not None and self.filter_current.isChecked():
|
||||||
|
return (self.current_name,)
|
||||||
|
return ()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filtered_properties(self):
|
||||||
|
ans = set()
|
||||||
|
a = ans.add
|
||||||
|
if self.opt_fonts.isChecked():
|
||||||
|
a('font-family')
|
||||||
|
if self.opt_margins.isChecked():
|
||||||
|
a('margin')
|
||||||
|
if self.opt_padding.isChecked():
|
||||||
|
a('padding')
|
||||||
|
if self.opt_floats.isChecked():
|
||||||
|
a('float'), a('clear')
|
||||||
|
if self.opt_colors.isChecked():
|
||||||
|
a('color'), a('background-color')
|
||||||
|
for x in unicode(self.others.text()).split(','):
|
||||||
|
x = x.strip()
|
||||||
|
if x:
|
||||||
|
a(x)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test(cls):
|
||||||
|
d = cls()
|
||||||
|
if d.exec_() == d.Accepted:
|
||||||
|
print (d.filtered_properties)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
InsertLink.test()
|
FilterCSS.test()
|
||||||
|
@ -178,6 +178,27 @@ class BuiltinCmp(BuiltinFormatterFunction):
|
|||||||
return eq
|
return eq
|
||||||
return gt
|
return gt
|
||||||
|
|
||||||
|
class BuiltinFirstMatchingCmp(BuiltinFormatterFunction):
|
||||||
|
name = 'first_matching_cmp'
|
||||||
|
category = 'Relational'
|
||||||
|
arg_count = -1
|
||||||
|
__doc__ = doc = _('first_matching_cmp(val, cmp1, result1, cmp2, r2, ..., else_result) -- '
|
||||||
|
'compares "val < cmpN" in sequence, returning resultN for '
|
||||||
|
'the first comparison that succeeds. Returns else_result '
|
||||||
|
'if no comparison succeeds. Example: '
|
||||||
|
'first_matching_cmp(10,5,"small",10,"middle",15,"large","giant") '
|
||||||
|
'returns "middle". The same example with a first value of 16 returns "giant".')
|
||||||
|
|
||||||
|
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||||
|
if (len(args) % 2) != 0:
|
||||||
|
raise ValueError(_('first_matching_cmp requires an even number of arguments'))
|
||||||
|
val = float(args[0] if args[0] and args[0] != 'None' else 0)
|
||||||
|
for i in range(1, len(args) - 1, 2):
|
||||||
|
c = float(args[i] if args[i] and args[i] != 'None' else 0)
|
||||||
|
if val < c:
|
||||||
|
return args[i+1]
|
||||||
|
return args[len(args)-1]
|
||||||
|
|
||||||
class BuiltinStrcat(BuiltinFormatterFunction):
|
class BuiltinStrcat(BuiltinFormatterFunction):
|
||||||
name = 'strcat'
|
name = 'strcat'
|
||||||
arg_count = -1
|
arg_count = -1
|
||||||
@ -1310,9 +1331,9 @@ _formatter_builtins = [
|
|||||||
BuiltinCapitalize(), BuiltinCmp(), BuiltinContains(), BuiltinCount(),
|
BuiltinCapitalize(), BuiltinCmp(), BuiltinContains(), BuiltinCount(),
|
||||||
BuiltinCurrentLibraryName(), BuiltinCurrentLibraryPath(),
|
BuiltinCurrentLibraryName(), BuiltinCurrentLibraryPath(),
|
||||||
BuiltinDaysBetween(), BuiltinDivide(), BuiltinEval(), BuiltinFirstNonEmpty(),
|
BuiltinDaysBetween(), BuiltinDivide(), BuiltinEval(), BuiltinFirstNonEmpty(),
|
||||||
BuiltinField(), BuiltinFinishFormatting(), BuiltinFormatDate(),
|
BuiltinField(), BuiltinFinishFormatting(), BuiltinFirstMatchingCmp(),
|
||||||
BuiltinFormatNumber(), BuiltinFormatsModtimes(), BuiltinFormatsPaths(),
|
BuiltinFormatDate(), BuiltinFormatNumber(), BuiltinFormatsModtimes(),
|
||||||
BuiltinFormatsSizes(),
|
BuiltinFormatsPaths(), BuiltinFormatsSizes(),
|
||||||
BuiltinHasCover(), BuiltinHumanReadable(), BuiltinIdentifierInList(),
|
BuiltinHasCover(), BuiltinHumanReadable(), BuiltinIdentifierInList(),
|
||||||
BuiltinIfempty(), BuiltinLanguageCodes(), BuiltinLanguageStrings(),
|
BuiltinIfempty(), BuiltinLanguageCodes(), BuiltinLanguageStrings(),
|
||||||
BuiltinInList(), BuiltinListDifference(), BuiltinListEquals(),
|
BuiltinInList(), BuiltinListDifference(), BuiltinListEquals(),
|
||||||
|
@ -140,6 +140,7 @@ class TestICU(unittest.TestCase):
|
|||||||
|
|
||||||
def test_contractions(self):
|
def test_contractions(self):
|
||||||
' Test contractions '
|
' Test contractions '
|
||||||
|
self.skipTest('Skipping as this depends too much on ICU version')
|
||||||
c = icu._icu.Collator('cs')
|
c = icu._icu.Collator('cs')
|
||||||
self.ae(icu.contractions(c), frozenset({u'Z\u030c', u'z\u030c', u'Ch',
|
self.ae(icu.contractions(c), frozenset({u'Z\u030c', u'z\u030c', u'Ch',
|
||||||
u'C\u030c', u'ch', u'cH', u'c\u030c', u's\u030c', u'r\u030c', u'CH',
|
u'C\u030c', u'ch', u'cH', u'c\u030c', u's\u030c', u'r\u030c', u'CH',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user