diff --git a/installer/linux/freeze.py b/installer/linux/freeze.py
index 1fc18d3600..8115c2fabd 100644
--- a/installer/linux/freeze.py
+++ b/installer/linux/freeze.py
@@ -93,7 +93,7 @@ def freeze():
'dateutil', 'dns', 'email']
includes += ['calibre.web.feeds.recipes.'+r for r in recipe_modules]
- includes += [x.split('/')[-1].rpartition('.')[0] for x in \
+ includes += ['calibre.gui2.convert.'+x.split('/')[-1].rpartition('.')[0] for x in \
glob.glob('src/calibre/gui2/convert/*.py')]
LOADER = '/tmp/loader.py'
diff --git a/src/calibre/debug.py b/src/calibre/debug.py
index 6714db0331..62582288e7 100644
--- a/src/calibre/debug.py
+++ b/src/calibre/debug.py
@@ -87,6 +87,7 @@ def setValue(self, val):
print 'Database migrated to', os.path.abspath(new)
def debug_device_driver():
+ from calibre.customize.ui import device_plugins
from calibre.devices.scanner import DeviceScanner
s = DeviceScanner()
s.scan()
@@ -113,17 +114,15 @@ def debug_device_driver():
raw = Device.run_ioreg()
open('/tmp/ioreg.txt', 'wb').write(raw)
print 'ioreg output saved to /tmp/ioreg.txt'
- from calibre.devices import devices
- for dev in devices():
- print 'Looking for', dev.__name__
+ for dev in device_plugins():
+ print 'Looking for', dev.__class__.__name__
connected = s.is_device_connected(dev)
if connected:
print 'Device Connected:', dev
print 'Trying to open device...'
- d = dev()
- d.open()
- print 'Main memory:', repr(d._main_prefix)
- print 'Total space:', d.total_space()
+ dev.open()
+ print 'Main memory:', repr(dev._main_prefix)
+ print 'Total space:', dev.total_space()
break
def add_simple_plugin(path_to_plugin):
diff --git a/src/calibre/devices/prs500/cli/main.py b/src/calibre/devices/prs500/cli/main.py
index 9211fcff41..53431f69af 100755
--- a/src/calibre/devices/prs500/cli/main.py
+++ b/src/calibre/devices/prs500/cli/main.py
@@ -3,14 +3,14 @@
"""
Provides a command-line and optional graphical interface to the SONY Reader PRS-500.
-For usage information run the script.
+For usage information run the script.
"""
import StringIO, sys, time, os
from optparse import OptionParser
from calibre import __version__, iswindows, __appname__
-from calibre.devices.errors import PathError
+from calibre.devices.errors import PathError
from calibre.utils.terminfo import TerminalController
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
from calibre.customize.ui import device_plugins
@@ -29,7 +29,7 @@ def human_readable(size):
return size + suffix
class FileFormatter(object):
- def __init__(self, file, term):
+ def __init__(self, file, term):
self.term = term
self.is_dir = file.is_dir
self.is_readonly = file.is_readonly
@@ -38,18 +38,18 @@ def __init__(self, file, term):
self.wtime = file.wtime
self.name = file.name
self.path = file.path
-
+
@dynamic_property
def mode_string(self):
doc=""" The mode string for this file. There are only two modes read-only and read-write """
def fget(self):
- mode, x = "-", "-"
+ mode, x = "-", "-"
if self.is_dir: mode, x = "d", "x"
if self.is_readonly: mode += "r-"+x+"r-"+x+"r-"+x
else: mode += "rw"+x+"rw"+x+"rw"+x
return mode
return property(doc=doc, fget=fget)
-
+
@dynamic_property
def isdir_name(self):
doc='''Return self.name + '/' if self is a directory'''
@@ -59,8 +59,8 @@ def fget(self):
name += '/'
return name
return property(doc=doc, fget=fget)
-
-
+
+
@dynamic_property
def name_in_color(self):
doc=""" The name in ANSI text. Directories are blue, ebooks are green """
@@ -71,24 +71,24 @@ def fget(self):
if self.is_dir: cname = blue + self.name + normal
else:
ext = self.name[self.name.rfind("."):]
- if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal
+ if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal
return cname
return property(doc=doc, fget=fget)
-
+
@dynamic_property
def human_readable_size(self):
doc=""" File size in human readable form """
def fget(self):
return human_readable(self.size)
return property(doc=doc, fget=fget)
-
+
@dynamic_property
def modification_time(self):
doc=""" Last modified time in the Linux ls -l format """
def fget(self):
return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
return property(doc=doc, fget=fget)
-
+
@dynamic_property
def creation_time(self):
doc=""" Last modified time in the Linux ls -l format """
@@ -104,7 +104,7 @@ def info(dev):
print "Mime type: ", info[3]
def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, ll=False, cols=0):
- def col_split(l, cols): # split list l into columns
+ def col_split(l, cols): # split list l into columns
rows = len(l) / cols
if len(l) % cols:
rows += 1
@@ -112,8 +112,8 @@ def col_split(l, cols): # split list l into columns
for i in range(rows):
m.append(l[i::rows])
return m
-
- def row_widths(table): # Calculate widths for each column in the row-wise table
+
+ def row_widths(table): # Calculate widths for each column in the row-wise table
tcols = len(table[0])
rowwidths = [ 0 for i in range(tcols) ]
for row in table:
@@ -122,19 +122,19 @@ def row_widths(table): # Calculate widths for each column in the row-wise table
rowwidths[c] = len(item) if len(item) > rowwidths[c] else rowwidths[c]
c += 1
return rowwidths
-
- output = StringIO.StringIO()
+
+ output = StringIO.StringIO()
if path.endswith("/") and len(path) > 1: path = path[:-1]
dirs = dev.list(path, recurse)
for dir in dirs:
- if recurse: print >>output, dir[0] + ":"
+ if recurse: print >>output, dir[0] + ":"
lsoutput, lscoloutput = [], []
files = dir[1]
maxlen = 0
if ll: # Calculate column width for size column
for file in files:
size = len(str(file.size))
- if human_readable_size:
+ if human_readable_size:
file = FileFormatter(file, term)
size = len(file.human_readable_size)
if size > maxlen: maxlen = size
@@ -148,29 +148,29 @@ def row_widths(table): # Calculate widths for each column in the row-wise table
size = str(file.size)
if human_readable_size: size = file.human_readable_size
print >>output, file.mode_string, ("%"+str(maxlen)+"s")%size, file.modification_time, name
- if not ll and len(lsoutput) > 0:
+ if not ll and len(lsoutput) > 0:
trytable = []
for colwidth in range(MINIMUM_COL_WIDTH, cols):
trycols = int(cols/colwidth)
- trytable = col_split(lsoutput, trycols)
+ trytable = col_split(lsoutput, trycols)
works = True
for row in trytable:
row_break = False
for item in row:
- if len(item) > colwidth - 1:
+ if len(item) > colwidth - 1:
works, row_break = False, True
break
if row_break: break
if works: break
rowwidths = row_widths(trytable)
trytablecol = col_split(lscoloutput, len(trytable[0]))
- for r in range(len(trytable)):
+ for r in range(len(trytable)):
for c in range(len(trytable[r])):
padding = rowwidths[c] - len(trytable[r][c])
print >>output, trytablecol[r][c], "".ljust(padding),
- print >>output
+ print >>output
print >>output
- listing = output.getvalue().rstrip()+ "\n"
+ listing = output.getvalue().rstrip()+ "\n"
output.close()
return listing
@@ -179,20 +179,20 @@ def main():
cols = term.COLS
if not cols: # On windows terminal width is unknown
cols = 80
-
+
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, books, df, ls, cp, mkdir, touch, cat, rm\n\n"+
"For help on a particular command: %prog command", version=__appname__+" version: " + __version__)
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
- "The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
+ "The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
dest="log_packets", action="store_true", default=False)
parser.remove_option("-h")
parser.disable_interspersed_args() # Allow unrecognized options
options, args = parser.parse_args()
-
+
if len(args) < 1:
parser.print_help()
return 1
-
+
command = args[0]
args = args[1:]
dev = None
@@ -207,27 +207,27 @@ def main():
if scanner.is_device_connected(d):
dev = d
dev.reset(log_packets=options.log_packets)
-
+
if dev is None:
print >>sys.stderr, 'Unable to find a connected ebook reader.'
return 1
-
+
try:
dev.open()
if command == "df":
total = dev.total_space(end_session=False)
free = dev.free_space()
where = ("Memory", "Stick", "Card")
- print "Filesystem\tSize \tUsed \tAvail \tUse%"
+ print "Filesystem\tSize \tUsed \tAvail \tUse%"
for i in range(3):
print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),\
str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%")
elif command == "books":
print "Books in main memory:"
- for book in dev.books():
+ for book in dev.books():
print book
print "\nBooks on storage card:"
- for book in dev.books(oncard=True): print book
+ for book in dev.books(oncard=True): print book
elif command == "mkdir":
parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/")
if len(args) != 1:
@@ -245,7 +245,7 @@ def main():
if len(args) != 1:
parser.print_help()
return 1
- print ls(dev, args[0], term, color=options.color, recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols),
+ print ls(dev, args[0], term, color=options.color, recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols),
elif command == "info":
info(dev)
elif command == "cp":
@@ -259,22 +259,22 @@ def main():
parser.add_option('-f', '--force', dest='force', action='store_true', default=False,
help='Overwrite the destination file if it exists already.')
options, args = parser.parse_args(args)
- if len(args) != 2:
+ if len(args) != 2:
parser.print_help()
return 1
if args[0].startswith("prs500:"):
outfile = args[1]
path = args[0][7:]
- if path.endswith("/"): path = path[:-1]
+ if path.endswith("/"): path = path[:-1]
if os.path.isdir(outfile):
- outfile = os.path.join(outfile, path[path.rfind("/")+1:])
+ outfile = os.path.join(outfile, path[path.rfind("/")+1:])
try:
outfile = open(outfile, "wb")
except IOError, e:
print >> sys.stderr, e
parser.print_help()
return 1
- dev.get_file(path, outfile)
+ dev.get_file(path, outfile)
outfile.close()
elif args[1].startswith("prs500:"):
try:
@@ -299,7 +299,7 @@ def main():
outfile = sys.stdout
parser = OptionParser(usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
options, args = parser.parse_args(args)
- if len(args) != 1:
+ if len(args) != 1:
parser.print_help()
return 1
if args[0].endswith("/"): path = args[0][:-1]
@@ -311,15 +311,15 @@ def main():
"and must begin with / or card:/\n\n"+\
"rm will DELETE the file. Be very CAREFUL")
options, args = parser.parse_args(args)
- if len(args) != 1:
+ if len(args) != 1:
parser.print_help()
return 1
- dev.rm(args[0])
+ dev.rm(args[0])
elif command == "touch":
parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+
"Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" )
options, args = parser.parse_args(args)
- if len(args) != 1:
+ if len(args) != 1:
parser.print_help()
return 1
dev.touch(args[0])
diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py
index e75f67223a..378f15cab1 100644
--- a/src/calibre/devices/prs505/driver.py
+++ b/src/calibre/devices/prs505/driver.py
@@ -60,9 +60,8 @@ def write_cache(prefix):
'''.encode('utf8'))
- return True
+ return True
except:
- self._card_prefix = None
import traceback
traceback.print_exc()
return False
@@ -226,5 +225,5 @@ def write_card_prefix(prefix, listid):
f.close()
write_card_prefix(self._card_a_prefix, 1)
write_card_prefix(self._card_b_prefix, 2)
-
+
self.report_progress(1.0, _('Sending metadata to device...'))
diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py
index 9b56509351..4ae8ecdd8a 100644
--- a/src/calibre/devices/usbms/device.py
+++ b/src/calibre/devices/usbms/device.py
@@ -6,7 +6,8 @@
device. This class handles device detection.
'''
-import os, subprocess, time, re
+import os, subprocess, time, re, sys, glob
+from itertools import repeat
from calibre.devices.interface import DevicePlugin
from calibre.devices.errors import DeviceError
@@ -35,6 +36,7 @@ class Device(DeviceConfig, DevicePlugin):
MAIN_MEMORY_VOLUME_LABEL = ''
STORAGE_CARD_VOLUME_LABEL = ''
+ STORAGE_CARD2_VOLUME_LABEL = None
FDI_TEMPLATE = \
'''
@@ -290,51 +292,172 @@ def get_card_prefix(pat):
self._card_a_prefix = get_card_prefix(card_a_pat)
self._card_b_prefix = get_card_prefix(card_b_pat)
- def open_linux(self):
- import dbus
- bus = dbus.SystemBus()
- hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
+ def find_device_nodes(self):
- def conditional_mount(dev):
- mmo = bus.get_object("org.freedesktop.Hal", dev)
- label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
- is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
- mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
- fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
- if is_mounted:
- return str(mount_point)
- mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
- dbus_interface='org.freedesktop.Hal.Device.Volume')
- return os.path.normpath('/media/'+label)+'/'
+ def walk(base):
+ base = os.path.abspath(os.path.realpath(base))
+ for x in os.listdir(base):
+ p = os.path.join(base, x)
+ if os.path.islink(p) or not os.access(p, os.R_OK):
+ continue
+ isfile = os.path.isfile(p)
+ yield p, isfile
+ if not isfile:
+ for y, q in walk(p):
+ yield y, q
- mm = hm.FindDeviceStringMatch(__appname__+'.mainvolume', self.__class__.__name__)
- if not mm:
- raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%(self.__class__.__name__,))
- self._main_prefix = None
- for dev in mm:
- try:
- self._main_prefix = conditional_mount(dev)+os.sep
- break
- except dbus.exceptions.DBusException:
+ def raw2num(raw):
+ raw = raw.lower()
+ if not raw.startswith('0x'):
+ raw = '0x' + raw
+ return int(raw, 16)
+
+ # Find device node based on vendor, product and bcd
+ d, j = os.path.dirname, os.path.join
+ usb_dir = None
+
+ def test(val, attr):
+ q = getattr(self, attr)
+ if q is None: return True
+ return q == val or val in q
+
+ for x, isfile in walk('/sys/devices'):
+ if isfile and x.endswith('idVendor'):
+ usb_dir = d(x)
+ for y in ('idProduct',):
+ if not os.access(j(usb_dir, y), os.R_OK):
+ usb_dir = None
+ continue
+ e = lambda q : raw2num(open(j(usb_dir, q)).read())
+ ven, prod = map(e, ('idVendor', 'idProduct'))
+ if not (test(ven, 'VENDOR_ID') and test(prod, 'PRODUCT_ID')):
+ usb_dir = None
+ continue
+ if self.BCD is not None:
+ if not os.access(j(usb_dir, 'bcdDevice'), os.R_OK) or \
+ not test(e('bcdDevice'), 'BCD'):
+ usb_dir = None
+ continue
+ else:
+ break
+ else:
+ break
+
+ if usb_dir is None:
+ raise DeviceError(_('Unable to detect the %s disk drive.')
+ %self.__class__.__name__)
+
+ devnodes, ok = [], {}
+ for x, isfile in walk(usb_dir):
+ if not isfile and '/block/' in x:
+ parts = x.split('/')
+ idx = parts.index('block')
+ if idx == len(parts)-2:
+ sz = j(x, 'size')
+ node = parts[idx+1]
+ try:
+ exists = int(open(sz).read()) > 0
+ if exists:
+ node = self.find_largest_partition(x)
+ ok[node] = True
+ else:
+ ok[node] = False
+ except:
+ ok[node] = False
+ if ok[node]:
+ devnodes.append(node)
+ devnodes += list(repeat(None, 3))
+ return tuple(['/dev/'+x if ok.get(x, False) else None for x in devnodes[:3]])
+
+ def node_mountpoint(self, node):
+ for line in open('/proc/mounts').readlines():
+ line = line.split()
+ if line[0] == node:
+ return line[1]
+ return None
+
+ def find_largest_partition(self, path):
+ node = path.split('/')[-1]
+ nodes = []
+ for x in glob.glob(path+'/'+node+'*'):
+ sz = x + '/size'
+
+ if not os.access(sz, os.R_OK):
continue
-
- if not self._main_prefix:
- raise DeviceError('Could not open device for reading. Try a reboot.')
-
- self._card_a_prefix = self._card_b_prefix = None
- cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
-
- def mount_card(dev):
try:
- return conditional_mount(dev)+os.sep
+ sz = int(open(sz).read())
except:
- import traceback
- print traceback
+ continue
+ if sz > 0:
+ nodes.append((x.split('/')[-1], sz))
- if len(cards) >= 1:
- self._card_a_prefix = mount_card(cards[0])
- if len(cards) >=2:
- self._card_b_prefix = mount_card(cards[1])
+ nodes.sort(cmp=lambda x, y: cmp(x[1], y[1]))
+ if not nodes:
+ return node
+ return nodes[-1][0]
+
+
+ def open_linux(self):
+
+ def mount(node, type):
+ mp = self.node_mountpoint(node)
+ if mp is not None:
+ return mp, 0
+ if type == 'main':
+ label = self.MAIN_MEMORY_VOLUME_LABEL
+ if type == 'carda':
+ label = self.STORAGE_CARD_VOLUME_LABEL
+ if type == 'cardb':
+ label = self.STORAGE_CARD2_VOLUME_LABEL
+ if label is None:
+ label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
+ extra = 0
+ label = label.replace(' ', '_')
+ while True:
+ q = '_(%d)'%extra if extra else ''
+ if not os.path.exists('/media/'+label+q):
+ break
+ extra += 1
+ if extra:
+ label += '_(%d)'%extra
+
+ def do_mount(node, label):
+ cmd = ['pmount', '-w', '-s']
+ try:
+ p = subprocess.Popen(cmd + [node, label])
+ except OSError:
+ raise DeviceError(_('You must install the pmount package.'))
+ while p.poll() is None:
+ time.sleep(0.1)
+ return p.returncode
+
+ ret = do_mount(node, label)
+ if ret != 0:
+ return None, ret
+ return self.node_mountpoint(node)+'/', 0
+
+
+ main, carda, cardb = self.find_device_nodes()
+ if main is None:
+ raise DeviceError(_('Unable to detect the %s disk drive.')
+ %self.__class__.__name__)
+
+ mp, ret = mount(main, 'main')
+ if mp is None:
+ raise DeviceError(
+ _('Unable to mount main memory (Error code: %d)')%ret)
+ if not mp.endswith('/'): mp += '/'
+ self._main_prefix = mp
+ cards = [x for x in (carda, cardb) if x is not None]
+ prefix, typ = '_card_a_prefix', 'carda'
+ for card in cards:
+ mp, ret = mount(card, typ)
+ if mp is None:
+ print >>sys.stderr, 'Unable to mount card (Error code: %d)'%ret
+ else:
+ if not mp.endswith('/'): mp += '/'
+ setattr(self, prefix, mp)
+ prefix, typ = '_card_b_prefix', 'cardb'
def open(self):
time.sleep(5)
diff --git a/src/calibre/ebooks/__init__.py b/src/calibre/ebooks/__init__.py
index 416fe61789..b24b74f48c 100644
--- a/src/calibre/ebooks/__init__.py
+++ b/src/calibre/ebooks/__init__.py
@@ -23,7 +23,7 @@ class DRMError(ValueError):
pass
BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm',
- 'html', 'xhtml', 'pdf', 'prc', 'mobi', 'azw',
+ 'html', 'xhtml', 'pdf', 'prc', 'mobi', 'azw', 'doc',
'epub', 'fb2', 'djvu', 'lrx', 'cbr', 'cbz', 'oebzip',
'rb', 'imp', 'odt']
diff --git a/src/calibre/ebooks/lit/output.py b/src/calibre/ebooks/lit/output.py
index c72d8eae96..2a08ff51a8 100644
--- a/src/calibre/ebooks/lit/output.py
+++ b/src/calibre/ebooks/lit/output.py
@@ -7,8 +7,7 @@
__docformat__ = 'restructuredtext en'
-from calibre.customize.conversion import OutputFormatPlugin, \
- OptionRecommendation
+from calibre.customize.conversion import OutputFormatPlugin
class LITOutput(OutputFormatPlugin):
@@ -16,10 +15,6 @@ class LITOutput(OutputFormatPlugin):
author = 'Marshall T. Vandegrift'
file_type = 'lit'
- recommendations = set([
- ('dont_split_on_page_breaks', False, OptionRecommendation.HIGH),
- ])
-
def convert(self, oeb, output_path, input_plugin, opts, log):
self.log, self.opts, self.oeb = log, opts, oeb
from calibre.ebooks.oeb.transforms.manglecase import CaseMangler
@@ -27,9 +22,7 @@ def convert(self, oeb, output_path, input_plugin, opts, log):
from calibre.ebooks.oeb.transforms.htmltoc import HTMLTOCAdder
from calibre.ebooks.lit.writer import LitWriter
from calibre.ebooks.oeb.transforms.split import Split
- split = Split(not self.opts.dont_split_on_page_breaks,
- max_flow_size=0
- )
+ split = Split(split_on_page_breaks=True, max_flow_size=0)
split(self.oeb, self.opts)
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 183ba73e04..a9a5556afa 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -2,7 +2,7 @@
__copyright__ = '2008, Kovid Goyal '
''' Post installation script for linux '''
import sys, os, shutil
-from subprocess import check_call, call
+from subprocess import check_call
from calibre import __version__, __appname__
from calibre.customize.ui import device_plugins
@@ -263,49 +263,6 @@ def setup_udev_rules(group_file, reload, fatal_errors):
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
)
udev.close()
- fdi = open_file('/usr/share/hal/fdi/policy/20thirdparty/10-calibre.fdi')
- manifest.append(fdi.name)
- fdi.write('\n\n\n')
- for cls in DEVICES:
- fdi.write(\
-'''
-
-
-
-
- %(cls)s
-
-
-
-
-'''%dict(cls=cls.__class__.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID,
- prog=__appname__, bcd=cls.BCD))
- fdi.write('\n'+cls.get_fdi())
- fdi.write('\n\n')
- fdi.close()
- if reload:
- called = False
- for hal in ('hald', 'hal', 'haldaemon'):
- hal = os.path.join('/etc/init.d', hal)
- if os.access(hal, os.X_OK):
- call((hal, 'restart'))
- called = True
- break
- if not called and os.access('/etc/rc.d/rc.hald', os.X_OK):
- call(('/etc/rc.d/rc.hald', 'restart'))
-
- try:
- check_call('udevadm control --reload_rules', shell=True)
- except:
- try:
- check_call('udevcontrol reload_rules', shell=True)
- except:
- try:
- check_call('/etc/init.d/udev reload', shell=True)
- except:
- if fatal_errors:
- raise Exception("Couldn't reload udev, you may have to reboot")
- print >>sys.stderr, "Couldn't reload udev, you may have to reboot"
return manifest
def option_parser():
@@ -314,7 +271,7 @@ def option_parser():
parser.add_option('--use-destdir', action='store_true', default=False, dest='destdir',
help='If set, respect the environment variable DESTDIR when installing files')
parser.add_option('--do-not-reload-udev-hal', action='store_true', dest='dont_reload', default=False,
- help='If set, do not try to reload udev rules and HAL FDI files')
+ help='Does nothing. Present for legacy reasons.')
parser.add_option('--group-file', default='/etc/group', dest='group_file',
help='File from which to read group information. Default: %default')
parser.add_option('--dont-check-root', action='store_true', default=False, dest='no_root',
diff --git a/src/calibre/trac/plugins/download.py b/src/calibre/trac/plugins/download.py
index 72105cd68f..2372f14f86 100644
--- a/src/calibre/trac/plugins/download.py
+++ b/src/calibre/trac/plugins/download.py
@@ -21,6 +21,7 @@
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
('poppler', '0.10.5', 'poppler', 'poppler', 'poppler', 'poppler'),
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
+ ('pmount', '0.9.19', 'pmount', 'pmount', 'pmount', 'pmount'),
]
diff --git a/src/calibre/web/feeds/recipes/__init__.py b/src/calibre/web/feeds/recipes/__init__.py
index 4021b258f9..a6dabf230f 100644
--- a/src/calibre/web/feeds/recipes/__init__.py
+++ b/src/calibre/web/feeds/recipes/__init__.py
@@ -44,7 +44,8 @@
'stackoverflow', 'telepolis_artikel', 'zaobao', 'usnews',
'straitstimes', 'index_hu', 'pcworld_hu', 'hrt', 'rts',
'h1', 'h2', 'h3', 'phd_comics', 'woz_die', 'elektrolese',
- 'climate_progress', 'carta', 'slashdot',
+ 'climate_progress', 'carta', 'slashdot', 'publico',
+ 'the_budget_fashionista'
)]
import re, imp, inspect, time, os
diff --git a/src/calibre/web/feeds/recipes/recipe_publico.py b/src/calibre/web/feeds/recipes/recipe_publico.py
new file mode 100644
index 0000000000..17e168955f
--- /dev/null
+++ b/src/calibre/web/feeds/recipes/recipe_publico.py
@@ -0,0 +1,40 @@
+"""
+publico.py - v1.0
+
+Copyright (c) 2009, David Rodrigues - http://sixhat.net
+All rights reserved.
+"""
+
+__license__ = 'GPL 3'
+
+from calibre.web.feeds.news import BasicNewsRecipe
+import re
+
+class Publico(BasicNewsRecipe):
+ title = u'P\xc3\xbablico'
+ __author__ = 'David Rodrigues'
+ oldest_article = 1
+ max_articles_per_feed = 30
+ encoding='utf-8'
+ no_stylesheets = True
+ language = _('Portuguese')
+ preprocess_regexps = [(re.compile(u"\uFFFD", re.DOTALL|re.IGNORECASE), lambda match: ''),]
+
+ feeds = [
+ (u'Geral', u'http://feeds.feedburner.com/PublicoUltimaHora'),
+ (u'Internacional', u'http://www.publico.clix.pt/rss.ashx?idCanal=11'),
+ (u'Pol\xc3\xadtica', u'http://www.publico.clix.pt/rss.ashx?idCanal=12'),
+ (u'Ci\xc3\xaancias', u'http://www.publico.clix.pt/rss.ashx?idCanal=13'),
+ (u'Desporto', u'http://desporto.publico.pt/rss.ashx'),
+ (u'Economia', u'http://www.publico.clix.pt/rss.ashx?idCanal=57'),
+ (u'Educa\xc3\xa7\xc3\xa3o', u'http://www.publico.clix.pt/rss.ashx?idCanal=58'),
+ (u'Local', u'http://www.publico.clix.pt/rss.ashx?idCanal=59'),
+ (u'Media e Tecnologia', u'http://www.publico.clix.pt/rss.ashx?idCanal=61'),
+ (u'Sociedade', u'http://www.publico.clix.pt/rss.ashx?idCanal=62')
+ ]
+ remove_tags = [dict(name='script'), dict(id='linhaTitulosHeader')]
+ keep_only_tags = [dict(name='div')]
+
+ def print_version(self,url):
+ s=re.findall("id=[0-9]+",url);
+ return "http://ww2.publico.clix.pt/print.aspx?"+s[0]
diff --git a/src/calibre/web/feeds/recipes/recipe_the_budget_fashionista.py b/src/calibre/web/feeds/recipes/recipe_the_budget_fashionista.py
new file mode 100644
index 0000000000..113cf9ce43
--- /dev/null
+++ b/src/calibre/web/feeds/recipes/recipe_the_budget_fashionista.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+__license__ = 'GPL v3'
+__copyright__ = '2009, Darko Miletic '
+'''
+www.thebudgetfashionista.com
+'''
+
+import re
+from calibre.web.feeds.recipes import BasicNewsRecipe
+from calibre.ebooks.BeautifulSoup import Tag
+
+class TheBudgetFashionista(BasicNewsRecipe):
+ title = 'The Budget Fashionista'
+ __author__ = 'Darko Miletic'
+ description = 'Saving your money since 2003'
+ oldest_article = 7
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ encoding = 'utf-8'
+ publisher = 'TBF GROUP, LLC.'
+ category = 'news, fashion, comsetics, women'
+ lang = 'en-US'
+ language = _('English')
+
+ preprocess_regexps = [(re.compile(r"{0,1}", re.DOTALL|re.IGNORECASE),lambda match: '')]
+
+ html2lrf_options = [
+ '--comment', description
+ , '--category', category
+ , '--publisher', publisher
+ ]
+
+ html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
+
+ keep_only_tags = [dict(name='div', attrs={'id':'singlepost'})]
+ remove_tags_after = dict(name='div', attrs={'id':'postnav'})
+ remove_tags = [
+ dict(name=['object','link','script','iframe','form'])
+ ,dict(name='div', attrs={'id':'postnav'})
+ ]
+
+ feeds = [(u'Articles', u'http://www.thebudgetfashionista.com/feeds/atom/')]
+
+ def preprocess_html(self, soup):
+ for item in soup.findAll(style=True):
+ del item['style']
+ return soup
+
+ def postprocess_html(self, soup, x):
+ body = soup.find('body')
+ post = soup.find('div', attrs={'id':'singlepost'})
+ if post and body:
+ post.extract()
+ body.extract()
+ soup.html.append(body)
+ body.insert(1,post)
+ mlang = Tag(soup,'meta',[("http-equiv","Content-Language"),("content",self.lang)])
+ mcharset = Tag(soup,'meta',[("http-equiv","Content-Type"),("content","text/html; charset=utf-8")])
+ soup.head.insert(0,mlang)
+ soup.head.insert(1,mcharset)
+ return self.adeify_images(soup)