KG updates Qt 4.7

This commit is contained in:
GRiker 2010-11-16 15:30:36 -07:00
commit 179f8853dc
28 changed files with 438 additions and 213 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__copyright__ = '2010, Szing'
__docformat__ = 'restructuredtext en'
'''
@ -10,49 +10,52 @@ globeandmail.com
from calibre.web.feeds.news import BasicNewsRecipe
class GlobeAndMail(BasicNewsRecipe):
title = u'Globe and Mail'
language = 'en_CA'
__author__ = 'Kovid Goyal'
class AdvancedUserRecipe1287083651(BasicNewsRecipe):
title = u'Globe & Mail'
__license__ = 'GPL v3'
__author__ = 'Szing'
oldest_article = 2
max_articles_per_feed = 10
no_stylesheets = True
extra_css = '''
h3 {font-size: 22pt; font-weight:bold; margin:0px; padding:0px 0px 8pt 0px;}
h4 {margin-top: 0px;}
#byline { font-family: monospace; font-weight:bold; }
#placeline {font-weight:bold;}
#credit {margin-top:0px;}
.tag {font-size: 22pt;}'''
description = 'Canada\'s national newspaper'
keep_only_tags = [dict(name='article')]
remove_tags = [dict(name='aside'),
dict(name='footer'),
dict(name='div', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articlecommentcountholder' in x.split(' '))}),
dict(name='ul', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articletoolbar' in x.split(' '))}),
]
feeds = [
(u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'),
(u'Top stories', u'http://www.theglobeandmail.com/?service=rss&feed=topstories'),
(u'National', u'http://www.theglobeandmail.com/news/national/?service=rss'),
(u'Politics', u'http://www.theglobeandmail.com/news/politics/?service=rss'),
(u'World', u'http://www.theglobeandmail.com/news/world/?service=rss'),
(u'Business', u'http://www.theglobeandmail.com/report-on-business/?service=rss'),
(u'Opinions', u'http://www.theglobeandmail.com/news/opinions/?service=rss'),
(u'Columnists', u'http://www.theglobeandmail.com/news/opinions/columnists/?service=rss'),
(u'Globe Investor', u'http://www.theglobeandmail.com/globe-investor/?service=rss'),
(u'Sports', u'http://www.theglobeandmail.com/sports/?service=rss'),
(u'Technology', u'http://www.theglobeandmail.com/news/technology/?service=rss'),
(u'Arts', u'http://www.theglobeandmail.com/news/arts/?service=rss'),
(u'Life', u'http://www.theglobeandmail.com/life/?service=rss'),
(u'Blogs', u'http://www.theglobeandmail.com/blogs/?service=rss'),
(u'Real Estate', u'http://www.theglobeandmail.com/real-estate/?service=rss'),
(u'Auto', u'http://www.theglobeandmail.com/auto/?service=rss')
]
max_articles_per_feed = 100
encoding = 'utf8'
publisher = 'Globe & Mail'
language = 'en_CA'
extra_css = 'p.meta {font-size:75%}\n .redtext {color: red;}\n .byline {font-size: 70%}'
def get_article_url(self, article):
url = BasicNewsRecipe.get_article_url(self, article)
if '/video/' not in url:
return url
feeds = [
(u'Top National Stories', u'http://www.theglobeandmail.com/news/national/?service=rss'),
(u'Business', u'http://www.theglobeandmail.com/report-on-business/?service=rss'),
(u'Commentary', u'http://www.theglobeandmail.com/report-on-business/commentary/?service=rss'),
(u'Blogs', u'http://www.theglobeandmail.com/blogs/?service=rss'),
(u'Facts & Arguments', u'http://www.theglobeandmail.com/life/facts-and-arguments/?service=rss'),
(u'Technology', u'http://www.theglobeandmail.com/news/technology/?service=rss'),
(u'Investing', u'http://www.theglobeandmail.com/globe-investor/?service=rss'),
(u'Top Polical Stories', u'http://www.theglobeandmail.com/news/politics/?service=rss'),
(u'Arts', u'http://www.theglobeandmail.com/news/arts/?service=rss'),
(u'Life', u'http://www.theglobeandmail.com/life/?service=rss'),
(u'Real Estate', u'http://www.theglobeandmail.com/real-estate/?service=rss'),
(u'Auto', u'http://www.theglobeandmail.com/sports/?service=rss'),
(u'Sports', u'http://www.theglobeandmail.com/auto/?service=rss')
]
keep_only_tags = [
dict(name='h1'),
dict(name='h2', attrs={'id':'articletitle'}),
dict(name='p', attrs={'class':['leadText', 'meta', 'leadImage', 'redtext byline', 'bodyText']}),
dict(name='div', attrs={'class':['news','articlemeta','articlecopy']}),
dict(name='id', attrs={'class':'article'}),
dict(name='table', attrs={'class':'todays-market'}),
dict(name='header', attrs={'id':'leadheader'})
]
remove_tags = [
dict(name='div', attrs={'id':['tabInside', 'ShareArticles', 'topStories']})
]
#this has to be here or the text in the article appears twice.
remove_tags_after = [dict(id='article')]
#Use the mobile version rather than the web version
def print_version(self, url):
return url + '&service=mobile'

View File

@ -1,31 +1,33 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
'''
moscowtimes.ru
www.themoscowtimes.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Moscowtimes(BasicNewsRecipe):
title = u'The Moscow Times'
title = 'The Moscow Times'
__author__ = 'Darko Miletic and Sujata Raman'
description = 'News from Russia'
language = 'en'
lang = 'en'
oldest_article = 7
description = 'The Moscow Times is a daily English-language newspaper featuring objective, reliable news on business, politics, sports and culture in Moscow, in Russia and the former Soviet Union (CIS).'
category = 'Russia, Moscow, Russian news, Moscow news, Russian newspaper, daily news, independent news, reliable news, USSR, Soviet Union, CIS, Russian politics, Russian business, Russian culture, Russian opinion, St Petersburg, Saint Petersburg'
publisher = 'The Moscow Times'
language = 'en'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
#encoding = 'utf-8'
encoding = 'cp1252'
remove_javascript = True
remove_empty_feeds = True
encoding = 'cp1251'
masthead_url = 'http://www.themoscowtimes.com/bitrix/templates/tmt/img/logo.gif'
publication_type = 'newspaper'
conversion_options = {
'comment' : description
, 'language' : lang
}
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
extra_css = '''
h1{ color:#0066B3; font-family: Georgia,serif ; font-size: large}
@ -35,39 +37,37 @@ class Moscowtimes(BasicNewsRecipe):
.text{font-family:Arial,Tahoma,Verdana,Helvetica,sans-serif ; font-size:75%; }
'''
feeds = [
(u'The Moscow Times Top Stories' , u'http://www.themoscowtimes.com/rss/top'),
(u'The Moscow Times Current Issue' , u'http://www.themoscowtimes.com/rss/issue'),
(u'The Moscow Times News' , u'http://www.themoscowtimes.com/rss/news'),
(u'The Moscow Times Business' , u'http://www.themoscowtimes.com/rss/business'),
(u'The Moscow Times Art and Ideas' , u'http://www.themoscowtimes.com/rss/art'),
(u'The Moscow Times Opinion' , u'http://www.themoscowtimes.com/rss/opinion')
(u'Top Stories' , u'http://www.themoscowtimes.com/rss/top' )
,(u'Current Issue' , u'http://www.themoscowtimes.com/rss/issue' )
,(u'News' , u'http://www.themoscowtimes.com/rss/news' )
,(u'Business' , u'http://www.themoscowtimes.com/rss/business')
,(u'Art and Ideas' , u'http://www.themoscowtimes.com/rss/art' )
,(u'Opinion' , u'http://www.themoscowtimes.com/rss/opinion' )
]
keep_only_tags = [
dict(name='div', attrs={'class':['newstextblock']})
]
keep_only_tags = [dict(name='div', attrs={'id':'content'})]
remove_tags = [
dict(name='div', attrs={'class':['photo_nav']})
]
dict(name='div', attrs={'class':['photo_nav','phototext']})
,dict(name=['iframe','meta','base','link','embed','object'])
]
def preprocess_html(self, soup):
soup.html['xml:lang'] = self.lang
soup.html['lang'] = self.lang
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">'
soup.head.insert(0,mtag)
return self.adeify_images(soup)
for lnk in soup.findAll('a'):
if lnk.string is not None:
ind = self.tag_to_string(lnk)
lnk.replaceWith(ind)
return soup
def print_version(self, url):
return url.replace('.themoscowtimes.com/','.themoscowtimes.com/print/')
def get_cover_url(self):
cover_url = None
href = 'http://www.themoscowtimes.com/pdf/'
soup = self.index_to_soup(href)
soup = self.index_to_soup(href)
div = soup.find('div',attrs={'class':'left'})
a = div.find('a')
print a
if a :
cover_url = a.img['src']
if div:
a = div.find('a')
if a :
cover_url = 'http://www.themoscowtimes.com' + a.img['src']
return cover_url

View File

@ -0,0 +1,35 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Based on Lars Jacob's Taz Digiabo recipe
__license__ = 'GPL v3'
__copyright__ = '2010, Starson17'
import os, urllib2, zipfile
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ptempfile import PersistentTemporaryFile
class NowToronto(BasicNewsRecipe):
title = u'Now Toronto'
description = u'Now Toronto'
__author__ = 'Starson17'
conversion_options = {
'no_default_epub_cover' : True
}
def build_index(self):
epub_feed = "http://feeds.feedburner.com/NowEpubEditions"
soup = self.index_to_soup(epub_feed)
url = soup.find(name = 'feedburner:origlink').string
f = urllib2.urlopen(url)
tmp = PersistentTemporaryFile(suffix='.epub')
self.report_progress(0,_('downloading epub'))
tmp.write(f.read())
tmp.close()
zfile = zipfile.ZipFile(tmp.name, 'r')
self.report_progress(0,_('extracting epub'))
zfile.extractall(self.output_dir)
tmp.close()
index = os.path.join(self.output_dir, 'content.opf')
self.report_progress(1,_('epub downloaded and extracted'))
return index

View File

@ -0,0 +1,70 @@
#!/usr/bin/env python
from calibre.web.feeds.recipes import BasicNewsRecipe
class PCLab(BasicNewsRecipe):
cover_url = 'http://pclab.pl/img/logo.png'
title = u"PC Lab"
__author__ = 'ravcio - rlelusz[at]gmail.com'
description = u"Articles from PC Lab website"
language = 'pl'
oldest_article = 30.0
max_articles_per_feed = 100
recursions = 0
encoding = 'iso-8859-2'
no_stylesheets = True
remove_javascript = True
use_embedded_content = False
keep_only_tags = [
dict(name='div', attrs={'class':['substance']})
]
remove_tags = [
dict(name='div', attrs={'class':['chapters']})
,dict(name='div', attrs={'id':['script_bxad_slot_display_list_bxad_slot']})
]
remove_tags_after = [
dict(name='div', attrs={'class':['navigation']})
]
#links to RSS feeds
feeds = [ ('PCLab', u'http://pclab.pl/xml/artykuly.xml') ]
#load second and subsequent page content
# in: soup - full page with 'next' button
# out: appendtag - tag to which new page is to be added
def append_page(self, soup, appendtag):
# find the 'Next' button
pager = soup.find('div', attrs={'class':'next'})
if pager:
#search for 'a' element with link to next page (exit if not found)
a = pager.find('a')
if a:
nexturl = a['href']
soup2 = self.index_to_soup('http://pclab.pl/' + nexturl)
pagetext_substance = soup2.find('div', attrs={'class':'substance'})
pagetext = pagetext_substance.find('div', attrs={'class':'data'})
pagetext.extract()
pos = len(appendtag.contents)
appendtag.insert(pos, pagetext)
pos = len(appendtag.contents)
self.append_page(soup2, appendtag)
def preprocess_html(self, soup):
# soup.body contains no title and no navigator, they are in soup
self.append_page(soup, soup.body)
# finally remove some tags
tags = soup.findAll('div',attrs={'class':['tags', 'index', 'script_bxad_slot_display_list_bxad_slot', 'index first', 'zumi', 'navigation']})
[tag.extract() for tag in tags]
return soup

View File

@ -7,7 +7,7 @@ class AdvancedUserRecipe1284927619(BasicNewsRecipe):
__author__ = 'noxxx'
max_articles_per_feed = 100
description = 'tagesanzeiger.ch: Nichts verpassen'
category = 'News, Politik, Nachrichten, Schweiz, Zürich'
category = 'News, Politik, Nachrichten, Schweiz, Zuerich'
language = 'de'
conversion_options = {

View File

@ -13,9 +13,9 @@ from PyQt4 import pyqtconfig
from setup import isosx, iswindows, islinux
OSX_SDK = '/Developer/SDKs/MacOSX10.4u.sdk'
OSX_SDK = '/Developer/SDKs/MacOSX10.5.sdk'
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4'
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.5'
NMAKE = RC = msvc = MT = win_inc = win_lib = win_ddk = None
if iswindows:
@ -124,7 +124,7 @@ elif isosx:
fc_inc = '/sw/include/fontconfig'
fc_lib = '/sw/lib'
poppler_inc_dirs = consolidate('POPPLER_INC_DIR',
'/sw/build/poppler-0.12.2/poppler:/sw/build/poppler-0.12.2')
'/sw/build/poppler-0.14.5/poppler:/sw/build/poppler-0.14.5')
popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[0]+'/qt4']
poppler_lib_dirs = consolidate('POPPLER_LIB_DIR',
'/sw/lib')

View File

@ -19,7 +19,7 @@ __all__ = [
'upload_user_manual', 'upload_to_mobileread', 'upload_demo',
'upload_to_sourceforge', 'upload_to_google_code',
'linux32', 'linux64', 'linux', 'linux_freeze', 'linux_freeze2',
'osx32_freeze', 'osx32', 'osx', 'rsync', 'push',
'osx32_freeze', 'osx', 'rsync', 'push',
'win32_freeze', 'win32', 'win',
'stage1', 'stage2', 'stage3', 'stage4', 'publish'
]
@ -84,9 +84,8 @@ linux_freeze = LinuxFreeze()
from setup.installer.linux.freeze2 import LinuxFreeze2
linux_freeze2 = LinuxFreeze2()
from setup.installer.osx import OSX, OSX32
from setup.installer.osx import OSX
osx = OSX()
osx32 = OSX32()
from setup.installer.osx.app.main import OSX32_Freeze
osx32_freeze = OSX32_Freeze()

View File

@ -186,7 +186,7 @@ if isfreebsd:
if isosx:
x, p = ('i386', 'ppc')
x, p = ('i386', 'x86_64')
archs = ['-arch', x, '-arch', p, '-isysroot',
OSX_SDK]
cflags.append('-D_OSX')
@ -339,7 +339,7 @@ class Build(Command):
obj_pat = 'release\\*.obj' if iswindows else '*.o'
objects = glob.glob(obj_pat)
if not objects or self.newer(objects, ext.sources+ext.headers):
archs = 'x86 ppc'
archs = 'x86 x86_64'
pro = textwrap.dedent('''\
TARGET = %s
TEMPLATE = lib

View File

@ -7,25 +7,14 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from setup import Command
from setup.installer import VMInstaller
class OSX(Command):
class OSX(VMInstaller):
description = 'Build OS X binary installers'
sub_commands = ['osx32']
def run(self, opts):
pass
class OSX32(VMInstaller):
description = 'Build 32 bit OS X binary installer'
description = 'Build OS X binary installer'
INSTALLER_EXT = 'dmg'
VM_NAME = 'leopard_build'
VM_NAME = 'osx_build'
VM = '/vmware/bin/%s'%VM_NAME
FREEZE_TEMPLATE = 'python -OO setup.py {freeze_command}'
FREEZE_COMMAND = 'osx32_freeze'

View File

@ -48,14 +48,14 @@ def compile_launcher_lib(contents_dir, gcc, base):
fd = join(contents_dir, 'Frameworks')
dest = join(fd, 'calibre-launcher.dylib')
src = join(base, 'util.c')
cmd = [gcc] + '-Wall -arch i386 -arch ppc -dynamiclib -std=gnu99'.split() + [src] + \
cmd = [gcc] + '-Wall -arch i386 -arch x86_64 -dynamiclib -std=gnu99'.split() + [src] + \
['-I'+base] + \
['-I/Library/Frameworks/Python.framework/Versions/Current/Headers'] + \
['-I/sw/python/Python.framework/Versions/Current/Headers'] + \
'-current_version 1.0 -compatibility_version 1.0'.split() + \
'-fvisibility=hidden -o'.split() + [dest] + \
['-install_name',
'@executable_path/../Frameworks/'+os.path.basename(dest)] + \
['-framework', 'Python', '-framework', 'CoreFoundation', '-headerpad_max_install_names']
['-F/sw/python', '-framework', 'Python', '-framework', 'CoreFoundation', '-headerpad_max_install_names']
info('\t'+' '.join(cmd))
sys.stdout.flush()
subprocess.check_call(cmd)
@ -88,7 +88,7 @@ def compile_launchers(contents_dir, xprograms, pyver):
fsrc = '/tmp/%s.c'%program
with open(fsrc, 'wb') as f:
f.write(psrc)
cmd = [gcc, '-Wall', '-arch', 'ppc', '-arch', 'i386',
cmd = [gcc, '-Wall', '-arch', 'x86_64', '-arch', 'i386',
'-I'+base, fsrc, lib, '-o', out,
'-headerpad_max_install_names']
info('\t'+' '.join(cmd))
@ -108,14 +108,6 @@ def flipwritable(fn, mode=None):
os.chmod(fn, stat.S_IWRITE | old_mode)
return old_mode
def thin(path):
try:
subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64'])
info('\tThinning', path)
except:
return
else:
subprocess.check_call(['lipo', path, '-thin', 'x86_64', '-output', path])
STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
def strip_files(files, argv_max=(256 * 1024)):
@ -200,7 +192,6 @@ class Py2App(object):
self.copy_site()
self.create_exe()
if not test_launchers:
#self.thin_to_x86_64()
self.strip_files()
ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION)
@ -212,19 +203,6 @@ class Py2App(object):
shutil.copytree('resources', os.path.join(self.resources_dir,
'resources'))
@flush
def thin_to_x86_64(self):
info('\nThinning to x86_64')
for y in (self.frameworks_dir, join(self.resources_dir, 'Python')):
for x in os.walk(y):
for f in x[-1]:
f = join(x[0], f)
if not os.path.isfile(f): continue
for t in ('.so', '.dylib', '/Python'):
if f.endswith(t):
thin(f)
break
@flush
def strip_files(self):
info('\nStripping files...')
@ -270,10 +248,10 @@ class Py2App(object):
continue
for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/',
'/opt/local/lib/',
'/Library/Frameworks/Python.framework/', SW+'/freetype/lib/'):
SW+'/python/Python.framework/', SW+'/freetype/lib/'):
if x.startswith(y):
if y == '/Library/Frameworks/Python.framework/':
y = '/Library/Frameworks/'
if y == SW+'/python/Python.framework/':
y = SW+'/python/'
yield x, x[len(y):]
break
@ -299,7 +277,7 @@ class Py2App(object):
@flush
def add_python_framework(self):
info('\nAdding Python framework')
src = join('/Library/Frameworks', 'Python.framework')
src = join('/sw/python', 'Python.framework')
x = join(self.frameworks_dir, 'Python.framework')
curr = os.path.realpath(join(src, 'Versions', 'Current'))
currd = join(x, 'Versions', basename(curr))
@ -314,7 +292,7 @@ class Py2App(object):
def add_qt_frameworks(self):
info('\nAdding Qt Framework')
for f in ('QtCore', 'QtGui', 'QtXml', 'QtNetwork', 'QtSvg', 'QtWebKit',
'QtXmlPatterns', 'phonon'):
'QtXmlPatterns'):
self.add_qt_framework(f)
for d in glob.glob(join(SW, 'qt', 'plugins', '*')):
shutil.copytree(d, join(self.contents_dir, 'MacOS', basename(d)))
@ -353,8 +331,8 @@ class Py2App(object):
shutil.copy2(f, dest)
self.fix_dependencies_in_lib(join(dest, basename(f)))
if 'podofo' in f:
self.change_dep('libpodofo.0.6.99.dylib',
self.FID+'/'+'libpodofo.0.6.99.dylib', join(dest, basename(f)))
self.change_dep('libpodofo.0.8.4.dylib',
self.FID+'/'+'libpodofo.0.8.4.dylib', join(dest, basename(f)))
@flush
@ -401,25 +379,27 @@ class Py2App(object):
@flush
def add_podofo(self):
info('\nAdding PoDoFo')
pdf = join(SW, 'lib', 'libpodofo.0.8.2.dylib')
pdf = join(SW, 'lib', 'libpodofo.0.8.4.dylib')
self.install_dylib(pdf)
@flush
def add_poppler(self):
info('\nAdding poppler')
for x in ('libpoppler.5.dylib', 'libpoppler-qt4.3.dylib'):
for x in ('libpoppler.7.dylib',):
self.install_dylib(os.path.join(SW, 'lib', x))
self.install_dylib(os.path.join(SW, 'bin', 'pdftohtml'), False)
@flush
def add_libjpeg(self):
info('\nAdding libjpeg')
self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.7.dylib'))
self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.8.dylib'))
@flush
def add_libpng(self):
info('\nAdding libpng')
self.install_dylib(os.path.join(SW, 'lib', 'libpng12.0.dylib'))
self.install_dylib(os.path.join(SW, 'lib', 'libpng.3.dylib'))
@flush
def add_fontconfig(self):
@ -449,7 +429,7 @@ class Py2App(object):
def add_imagemagick(self):
info('\nAdding ImageMagick')
for x in ('Wand', 'Core'):
self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.2.dylib'%x))
self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.4.dylib'%x))
idir = glob.glob(os.path.join(SW, 'lib', 'ImageMagick-*'))[-1]
dest = os.path.join(self.frameworks_dir, 'ImageMagick')
if os.path.exists(dest):
@ -463,7 +443,8 @@ class Py2App(object):
@flush
def add_misc_libraries(self):
for x in ('usb', 'unrar', 'readline.6.0', 'wmflite-0.2.7', 'chm.0'):
for x in ('usb', 'unrar', 'readline.6.1', 'wmflite-0.2.7', 'chm.0',
'sqlite3.0'):
info('\nAdding', x)
x = 'lib%s.dylib'%x
shutil.copy2(join(SW, 'lib', x), self.frameworks_dir)
@ -551,7 +532,7 @@ class Py2App(object):
@flush
def add_stdlib(self):
info('\nAdding python stdlib')
src = '/Library/Frameworks/Python.framework/Versions/Current/lib/python'
src = '/sw/python/Python.framework/Versions/Current/lib/python'
src += self.version_info
dest = join(self.resources_dir, 'Python', 'lib', 'python')
dest += self.version_info

View File

@ -28,7 +28,7 @@ If there are no windows binaries already compiled for the version of python you
Run the following command to install python dependencies::
easy_install --always-unzip -U ipython mechanize pyreadline python-dateutil dnspython
easy_install --always-unzip -U ipython mechanize pyreadline python-dateutil dnspython cssutils clientform
Install BeautifulSoup 3.0.x manually into site-packages (3.1.x parses broken HTML very poorly)
@ -37,7 +37,7 @@ Qt
Extract Qt sourcecode to C:\Qt\4.x.x. Run configure and make::
configure -opensource -release -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license && nmake
configure -opensource -release -qt-zlib -qt-gif -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs && nmake
SIP
-----

View File

@ -503,7 +503,11 @@ class KOBO(USBMS):
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(book.path)
ContentID = self.contentid_from_path(book.path, ContentType)
datelastread = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime())
t = (ContentID,)
cursor.execute('select DateLastRead from Content where BookID is Null and ContentID = ?', t)
result = cursor.fetchone()
datelastread = result[0] if result[0] is not None else '1970-01-01T00:00:00'
t = (datelastread,ContentID,)

View File

@ -199,6 +199,8 @@ class PRS505(USBMS):
thumbnail_dir = os.path.join(prefix, *thumbnail_dir.split('/'))
relpath = os.path.relpath(filepath, prefix)
if relpath.startswith('..\\'):
relpath = relpath[3:]
thumbnail_dir = os.path.join(thumbnail_dir, relpath)
if not os.path.exists(thumbnail_dir):
os.makedirs(thumbnail_dir)

View File

@ -53,8 +53,8 @@
#define NUKE(x) Py_XDECREF(x); x = NULL;
/* This function only works on 10.5 and later
static PyObject* send2trash(PyObject *self, PyObject *args)
/* This function only works on 10.5 and later. Pass in a unicode object as path */
static PyObject* usbobserver_send2trash(PyObject *self, PyObject *args)
{
UInt8 *utf8_chars;
FSRef fp;
@ -73,7 +73,7 @@ static PyObject* send2trash(PyObject *self, PyObject *args)
}
Py_RETURN_NONE;
}
*/
static PyObject*
usbobserver_get_iokit_string_property(io_service_t dev, CFStringRef prop) {
@ -323,6 +323,9 @@ static PyMethodDef usbobserver_methods[] = {
{"get_mounted_filesystems", usbobserver_get_mounted_filesystems, METH_VARARGS,
"Get mapping of mounted filesystems. Mapping is from BSD name to mount point."
},
{"send2trash", usbobserver_send2trash, METH_VARARGS,
"send2trash(unicode object) -> Send specified file/dir to trash"
},
{NULL, NULL, 0, NULL}
};

View File

@ -363,11 +363,15 @@ class MobiMLizer(object):
if value == getattr(self.profile, prop):
result = '100%'
else:
# Amazon's renderer does not support
# img sizes in units other than px
# See #7520 for test case
try:
ems = int(round(float(value) / self.profile.fbase))
pixs = int(round(float(value) / \
(72./self.profile.dpi)))
except:
continue
result = "%dem" % ems
result = "%d"%pixs
istate.attrib[prop] = result
elif tag == 'hr' and asfloat(style['width']) > 0:
prop = style['width'] / self.profile.width

View File

@ -620,6 +620,7 @@ static string get_link_dest(LinkAction *link, PDFDoc *doc) {
case actionSound: break;
case actionJavaScript: break;
case actionUnknown: break;
default: break;
}
return oss.str();
}

View File

@ -223,7 +223,6 @@ class MessageBox(QMessageBox):
if default_button is not None:
self.setDefaultButton(default_button)
def copy_to_clipboard(self):
QApplication.clipboard().setText('%s: %s\n\n%s' %
(self.title, self.msg, self.det_msg))

View File

@ -212,9 +212,9 @@ class BookInfo(QWebView):
def _show_data(self, rows, comments):
f = QFontInfo(QApplication.font(self.parent())).pixelSize()
p = unicode(QApplication.palette().color(QPalette.Normal,
QPalette.Base).name())
QPalette.Window).name())
c = unicode(QApplication.palette().color(QPalette.Normal,
QPalette.Text).name())
QPalette.WindowText).name())
templ = u'''\
<html>
<head>

View File

@ -14,7 +14,7 @@ from PyQt4.QtGui import QDialog, QItemSelectionModel
from calibre.gui2.dialogs.fetch_metadata_ui import Ui_FetchMetadata
from calibre.gui2 import error_dialog, NONE, info_dialog, config
from calibre.gui2.widgets import ProgressIndicator
from calibre import strftime
from calibre import strftime, force_unicode
from calibre.customize.ui import get_isbndb_key, set_isbndb_key
_hung_fetchers = set([])
@ -179,7 +179,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
self.terminate()
return self.queue_reject.emit()
self.model = Matches(self.fetcher.results)
warnings = [(x[0], unicode(x[1])) for x in \
warnings = [(x[0], force_unicode(x[1])) for x in \
self.fetcher.exceptions if x[1] is not None]
if warnings:
warnings='<br>'.join(['<b>%s</b>: %s'%(name, exc) for name,exc in warnings])

View File

@ -98,7 +98,7 @@ class MyBlockingBusy(QDialog):
return self.accept()
def do_one(self, id):
remove, add, au, aus, do_aus, rating, pub, do_series, \
remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \
do_autonumber, do_remove_format, remove_format, do_swap_ta, \
do_remove_conv, do_auto_author, series, do_series_restart, \
series_start_value, do_title_case, clear_series = self.args
@ -168,6 +168,8 @@ class MyBlockingBusy(QDialog):
# both of these are fast enough to just do them all
for w in self.cc_widgets:
w.commit(self.ids)
if remove_all:
self.db.remove_all_tags(self.ids)
self.db.bulk_modify_tags(self.ids, add=add, remove=remove,
notify=False)
self.current_index = len(self.ids)
@ -640,9 +642,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
for w in getattr(self, 'custom_column_widgets', []):
w.gui_val
if self.remove_all_tags.isChecked():
remove = self.db.all_tags()
else:
remove_all = self.remove_all_tags.isChecked()
remove = []
if not remove_all:
remove = unicode(self.remove_tags.text()).strip().split(',')
add = unicode(self.tags.text()).strip().split(',')
au = unicode(self.authors.text())
@ -663,7 +665,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
do_auto_author = self.auto_author_sort.isChecked()
do_title_case = self.change_title_to_title_case.isChecked()
args = (remove, add, au, aus, do_aus, rating, pub, do_series,
args = (remove_all, remove, add, au, aus, do_aus, rating, pub, do_series,
do_autonumber, do_remove_format, remove_format, do_swap_ta,
do_remove_conv, do_auto_author, series, do_series_restart,
series_start_value, do_title_case, clear_series)

View File

@ -308,6 +308,9 @@ from the value in the box</string>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>990000</number>
</property>
<property name="value">
<number>1</number>
</property>
@ -660,8 +663,8 @@ nothing should be put between the original text and the inserted text</string>
<rect>
<x>0</x>
<y>0</y>
<width>726</width>
<height>334</height>
<width>122</width>
<height>38</height>
</rect>
</property>
<layout class="QGridLayout" name="testgrid">

View File

@ -8,13 +8,15 @@ __docformat__ = 'restructuredtext en'
import cStringIO, sys
from binascii import hexlify, unhexlify
from functools import partial
from PyQt4.Qt import QWidget, pyqtSignal, QDialog, Qt
from PyQt4.Qt import QWidget, pyqtSignal, QDialog, Qt, QLabel, \
QLineEdit, QDialogButtonBox, QGridLayout, QCheckBox
from calibre.gui2.wizard.send_email_ui import Ui_Form
from calibre.utils.smtp import config as smtp_prefs
from calibre.gui2.dialogs.test_email_ui import Ui_Dialog as TE_Dialog
from calibre.gui2 import error_dialog, info_dialog
from calibre.gui2 import error_dialog
class TestEmail(QDialog, TE_Dialog):
@ -74,8 +76,9 @@ class SendEmail(QWidget, Ui_Form):
(self.relay_tls if opts.encryption == 'TLS' else self.relay_ssl).setChecked(True)
self.relay_tls.toggled.connect(self.changed)
self.relay_use_gmail.clicked.connect(
self.create_gmail_relay)
for x in ('gmail', 'hotmail'):
button = getattr(self, 'relay_use_'+x)
button.clicked.connect(partial(self.create_service_relay, x))
self.relay_show_password.stateChanged.connect(
lambda state : self.relay_password.setEchoMode(
self.relay_password.Password if
@ -114,19 +117,79 @@ class SendEmail(QWidget, Ui_Form):
sys.stdout, sys.stderr = oout, oerr
return tb
def create_gmail_relay(self, *args):
self.relay_username.setText('@gmail.com')
self.relay_password.setText('')
self.relay_host.setText('smtp.gmail.com')
self.relay_port.setValue(587)
def create_service_relay(self, service, *args):
service = {
'gmail': {
'name': 'Gmail',
'relay': 'smtp.gmail.com',
'port': 587,
'username': '@gmail.com',
'url': 'www.gmail.com',
'extra': ''
},
'hotmail': {
'name': 'Hotmail',
'relay': 'smtp.live.com',
'port': 587,
'username': '',
'url': 'www.hotmail.com',
'extra': _('If you are setting up a new'
' hotmail account, you must log in to it '
' once before you will be able to send mails.'),
}
}[service]
d = QDialog(self)
l = QGridLayout()
d.setLayout(l)
bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
bb.accepted.connect(d.accept)
bb.rejected.connect(d.reject)
d.tl = QLabel('<p>'+_('You can sign up for a free {name} email '
'account at <a href="http://{url}">http://{url}</a>. {extra}').format(
**service))
l.addWidget(d.tl, 0, 0, 3, 0)
d.tl.setWordWrap(True)
d.tl.setOpenExternalLinks(True)
for name, label in (
['from_', _('Your %s &email address:')],
['username', _('Your %s &username:')],
['password', _('Your %s &password:')],
):
la = QLabel(label%service['name'])
le = QLineEdit(d)
setattr(d, name, le)
setattr(d, name+'_label', la)
r = l.rowCount()
l.addWidget(la, r, 0)
l.addWidget(le, r, 1)
la.setBuddy(le)
if name == 'password':
d.ptoggle = QCheckBox(_('&Show password'), d)
l.addWidget(d.ptoggle, r, 2)
d.ptoggle.stateChanged.connect(
lambda s: d.password.setEchoMode(d.password.Normal if s
== Qt.Checked else d.password.Password))
d.username.setText(service['username'])
d.password.setEchoMode(d.password.Password)
d.bl = QLabel('<p>' + _(
'If you plan to use email to send books to your Kindle, remember to'
' add the your %s email address to the allowed email addresses in your '
'Amazon.com Kindle management page.')%service['name'])
d.bl.setWordWrap(True)
l.addWidget(d.bl, l.rowCount(), 0, 3, 0)
l.addWidget(bb, l.rowCount(), 0, 3, 0)
d.setWindowTitle(_('Setup') + ' ' + service['name'])
d.resize(d.sizeHint())
bb.setVisible(True)
if d.exec_() != d.Accepted:
return
self.relay_username.setText(d.username.text())
self.relay_password.setText(d.password.text())
self.email_from.setText(d.from_.text())
self.relay_host.setText(service['relay'])
self.relay_port.setValue(service['port'])
self.relay_tls.setChecked(True)
info_dialog(self, _('Finish gmail setup'),
_('Dont forget to enter your gmail username and password. '
'You can sign up for a free gmail account at http://gmail.com')).exec_()
self.relay_username.setFocus(Qt.OtherFocusReason)
self.relay_username.setCursorPosition(0)
def set_email_settings(self, to_set):
from_ = unicode(self.email_from.text()).strip()
if to_set and not from_:

View File

@ -216,6 +216,26 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="relay_use_hotmail">
<property name="text">
<string>Use Hotmail</string>
</property>
<property name="icon">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/hotmail.png</normaloff>:/images/hotmail.png</iconset>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="test_email_button">
<property name="text">

View File

@ -36,33 +36,8 @@ from calibre.utils.config import prefs, tweaks
from calibre.utils.search_query_parser import saved_searches, set_saved_searches
from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
from calibre.utils.magick.draw import save_cover_data_to
from calibre.utils.recycle_bin import delete_file, delete_tree
if iswindows:
import calibre.utils.winshell as winshell
def delete_file(path):
try:
winshell.delete_file(path, silent=True, no_confirm=True)
except:
os.remove(path)
def delete_tree(path, permanent=False):
if permanent:
try:
# For completely mysterious reasons, sometimes a file is left open
# leading to access errors. If we get an exception, wait and hope
# that whatever has the file (the O/S?) lets go of it.
shutil.rmtree(path)
except:
traceback.print_exc()
time.sleep(1)
shutil.rmtree(path)
else:
try:
if not permanent:
winshell.delete_file(path, silent=True, no_confirm=True)
except:
delete_tree(path, permanent=True)
copyfile = os.link if hasattr(os, 'link') else shutil.copyfile
@ -983,10 +958,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
path = None
self.data.remove(id)
if path and os.path.exists(path):
try:
winshell.delete_file(path, no_confirm=True, silent=True)
except:
self.rmtree(path)
self.rmtree(path)
parent = os.path.dirname(path)
if len(os.listdir(parent)) == 0:
self.rmtree(parent)
@ -1759,6 +1731,18 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
ans.append(tag)
return ans
def remove_all_tags(self, ids, notify=False, commit=True):
self.conn.executemany(
'DELETE FROM books_tags_link WHERE book=?', [(x,) for x in ids])
self.dirtied(ids, commit=False)
if commit:
self.conn.commit()
for x in ids:
self.data.set(x, self.FIELD_MAP['tags'], '', row_is_id=True)
if notify:
self.notify('metadata', ids)
def bulk_modify_tags(self, ids, add=[], remove=[], notify=False):
add = self.cleanup_tags(add)
remove = self.cleanup_tags(remove)

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, shutil, time
from functools import partial
from calibre import isbytestring
from calibre.constants import iswindows, isosx, plugins, filesystem_encoding
recycle = None
if iswindows:
import calibre.utils.winshell as winshell
recycle = partial(winshell.delete_file, silent=True, no_confirm=True)
elif isosx:
u = plugins['usbobserver'][0]
if hasattr(u, 'send2trash'):
def recycle(path):
if isbytestring(path):
path = path.decode(filesystem_encoding)
u.send2trash(path)
def delete_file(path):
if callable(recycle):
try:
recycle(path)
return
except:
import traceback
traceback.print_exc()
os.remove(path)
def delete_tree(path, permanent=False):
if permanent:
try:
# For completely mysterious reasons, sometimes a file is left open
# leading to access errors. If we get an exception, wait and hope
# that whatever has the file (the O/S?) lets go of it.
shutil.rmtree(path)
except:
import traceback
traceback.print_exc()
time.sleep(1)
shutil.rmtree(path)
else:
if callable(recycle):
try:
recycle(path)
return
except:
import traceback
traceback.print_exc()
delete_tree(path, permanent=True)

View File

@ -101,8 +101,12 @@ def sendmail(msg, from_, to, localhost=None, verbose=0, timeout=30,
if encryption == 'SSL':
s.sock = s.file.sslobj
s.login(username, password)
s.sendmail(from_, to, msg)
return s.quit()
ret = None
try:
s.sendmail(from_, to, msg)
finally:
ret = s.quit()
return ret
def option_parser():
try: