mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
1e072040ba
@ -230,7 +230,7 @@ _check_symlinks_prescript()
|
||||
all_functions = main_functions['console'] + main_functions['gui']
|
||||
print
|
||||
print 'Adding PoDoFo'
|
||||
pdf = glob.glob(os.path.expanduser('/Volumes/sw/podofo/*.dylib'))[0]
|
||||
pdf = glob.glob(os.path.expanduser('/Volumes/sw/podofo/libpodofo.0.7.00.dylib'))[0]
|
||||
shutil.copyfile(pdf, os.path.join(frameworks_dir, os.path.basename(pdf)))
|
||||
|
||||
|
||||
@ -264,6 +264,14 @@ _check_symlinks_prescript()
|
||||
if os.path.exists(dst):
|
||||
shutil.rmtree(dst)
|
||||
shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False)
|
||||
for x in os.listdir('/usr/local/etc/fonts'):
|
||||
dst = os.path.join(frameworks_dir, x)
|
||||
y = os.path.join('/usr/local/etc/fonts', x)
|
||||
if os.path.isdir(dst):
|
||||
if os.path.exists(dst): shutil.rmtree(dst)
|
||||
shutil.copytree(y, dst)
|
||||
else:
|
||||
os.link(y, dst)
|
||||
|
||||
print
|
||||
print 'Adding IPython'
|
||||
|
4
setup.py
4
setup.py
@ -62,9 +62,9 @@ if __name__ == '__main__':
|
||||
|
||||
podofo_inc = '/usr/include/podofo' if islinux else \
|
||||
'C:\\podofo\\include\\podofo' if iswindows else \
|
||||
'/Volumes/sw/podofo/include/podofo'
|
||||
'/usr/local/include/podofo'
|
||||
podofo_lib = '/usr/lib' if islinux else r'C:\podofo' if iswindows else \
|
||||
'/Volumes/sw/podofo/lib'
|
||||
'/usr/local/lib'
|
||||
podofo_inc = os.environ.get('PODOFO_INC_DIR', podofo_inc)
|
||||
if os.path.exists(os.path.join(podofo_inc, 'podofo.h')):
|
||||
optional.append(Extension('calibre.plugins.podofo',
|
||||
|
@ -403,7 +403,8 @@ def fix_ids(main, carda, cardb):
|
||||
for child in db.root_element.childNodes:
|
||||
if child.nodeType == child.ELEMENT_NODE and child.hasAttribute('id'):
|
||||
id_map[child.getAttribute('id')] = str(cid)
|
||||
child.setAttribute("sourceid", '1')
|
||||
child.setAttribute("sourceid",
|
||||
'0' if getattr(child, 'tagName', '').endswith('playlist') else '1')
|
||||
child.setAttribute('id', str(cid))
|
||||
cid += 1
|
||||
|
||||
|
@ -7,14 +7,7 @@ intended to be subclassed with the relevant parts implemented for a particular
|
||||
device. This class handles device detection.
|
||||
'''
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
import os, subprocess, time, re, sys, glob
|
||||
from itertools import repeat
|
||||
|
||||
from calibre.devices.interface import DevicePlugin
|
||||
@ -499,29 +492,26 @@ class Device(DeviceConfig, DevicePlugin):
|
||||
self.open_osx()
|
||||
|
||||
def eject_windows(self):
|
||||
win32file = __import__('win32file', globals(), locals(), [], -1)
|
||||
win32con = __import__('win32con', globals(), locals(), [], -1)
|
||||
win32shell = __import__('win32com.shell.shell', globals(), locals(), [], -1)
|
||||
win32shellcon = __import__('win32com.shell.shellcon', globals(), locals(), [], -1)
|
||||
|
||||
FSCTL_LOCK_VOLUME = 0x0090018
|
||||
FSCTL_DISMOUNT_VOLUME = 0x00090020
|
||||
IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804
|
||||
IOCTL_STORAGE_EJECT_MEDIA = 0x002D4808
|
||||
|
||||
from calibre.constants import plugins
|
||||
from threading import Thread
|
||||
winutil, winutil_err = plugins['winutil']
|
||||
drives = []
|
||||
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
|
||||
x = getattr(self, x, None)
|
||||
if x is not None:
|
||||
vol = win32file.CreateFile(x, win32con.GENERIC_READ | win32con.GENERIC_WRITE, win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE, None, win32con.OPEN_EXISTING, 0, None)
|
||||
drives.append(x[0].upper())
|
||||
|
||||
def do_it(drives):
|
||||
for d in drives:
|
||||
try:
|
||||
win32file.DeviceIoControl(vol, FSCTL_LOCK_VOLUME, '', 0, None)
|
||||
win32file.DeviceIoControl(vol, FSCTL_DISMOUNT_VOLUME, '', 0, None)
|
||||
win32file.DeviceIoControl(vol, IOCTL_STORAGE_MEDIA_REMOVAL, struct.pack('B', 0), 0, None)
|
||||
win32file.DeviceIoControl(vol, IOCTL_STORAGE_EJECT_MEDIA, '', 0, None)
|
||||
time.sleep(2)
|
||||
win32shell.SHChangeNotify(win32shellcon.SHCNE_DRIVEREMOVED, win32shellcon.SHCNF_PATH, x)
|
||||
finally:
|
||||
win32file.CloseHandle(vol)
|
||||
winutil.eject_drive(d)
|
||||
except:
|
||||
pass
|
||||
|
||||
t = Thread(target=do_it, args=[drives])
|
||||
t.daemon = True
|
||||
t.start()
|
||||
self.__save_win_eject_thread = t
|
||||
|
||||
def eject_osx(self):
|
||||
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
|
||||
|
@ -63,9 +63,12 @@ def roman(num):
|
||||
def fmt_sidx(i, fmt='%.2f', use_roman=False):
|
||||
if i is None:
|
||||
i = 1
|
||||
if int(i) == i:
|
||||
return roman(i) if use_roman else '%d'%i
|
||||
return fmt%i
|
||||
if int(i) == float(i):
|
||||
return roman(int(i)) if use_roman else '%d'%int(i)
|
||||
try:
|
||||
return fmt%i
|
||||
except TypeError:
|
||||
return fmt%float(i)
|
||||
|
||||
|
||||
class Resource(object):
|
||||
|
@ -77,6 +77,7 @@ class Query(object):
|
||||
if verbose:
|
||||
print 'Query:', self.url
|
||||
feed = etree.fromstring(browser.open(self.url).read())
|
||||
#print etree.tostring(feed, pretty_print=True)
|
||||
total = int(total_results(feed)[0].text)
|
||||
start = int(start_index(feed)[0].text)
|
||||
entries = entry(feed)
|
||||
@ -104,12 +105,9 @@ class ResultList(list):
|
||||
except:
|
||||
report(verbose)
|
||||
|
||||
|
||||
|
||||
def get_title(self, entry):
|
||||
candidates = [x.text for x in title(entry)]
|
||||
candidates.sort(cmp=lambda x,y: cmp(len(x), len(y)), reverse=True)
|
||||
return candidates[0]
|
||||
return ': '.join(candidates)
|
||||
|
||||
def get_authors(self, entry):
|
||||
m = creator(entry)
|
||||
@ -182,7 +180,7 @@ class ResultList(list):
|
||||
self.get_identifiers(x, mi)
|
||||
mi.tags = self.get_tags(x, verbose)
|
||||
mi.publisher = self.get_publisher(x, verbose)
|
||||
mi.timestamp = self.get_date(x, verbose)
|
||||
mi.pubdate = self.get_date(x, verbose)
|
||||
mi.language = self.get_language(x, verbose)
|
||||
self.append(mi)
|
||||
|
||||
|
@ -7,14 +7,18 @@ __docformat__ = 'restructuredtext en'
|
||||
HTTP server for remote access to the calibre database.
|
||||
'''
|
||||
|
||||
import sys, textwrap, operator, os, re, logging
|
||||
import sys, textwrap, operator, os, re, logging, cStringIO
|
||||
from itertools import repeat
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from datetime import datetime
|
||||
from threading import Thread
|
||||
|
||||
import cherrypy
|
||||
from PyQt4.Qt import QImage, QApplication, QByteArray, Qt, QBuffer
|
||||
try:
|
||||
from PIL import Image as PILImage
|
||||
PILImage
|
||||
except ImportError:
|
||||
import Image as PILImage
|
||||
|
||||
from calibre.constants import __version__, __appname__
|
||||
from calibre.utils.genshi.template import MarkupTemplate
|
||||
@ -195,25 +199,21 @@ class LibraryServer(object):
|
||||
updated = datetime.utcfromtimestamp(os.stat(path).st_mtime) if path and os.access(path, os.R_OK) else build_time
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
try:
|
||||
if QApplication.instance() is None:
|
||||
QApplication([])
|
||||
|
||||
im = QImage()
|
||||
im.loadFromData(cover)
|
||||
if im.isNull():
|
||||
f = cStringIO.StringIO(cover)
|
||||
try:
|
||||
im = PILImage.open(f)
|
||||
except IOError:
|
||||
raise cherrypy.HTTPError(404, 'No valid cover found')
|
||||
width, height = im.width(), im.height()
|
||||
width, height = im.size
|
||||
scaled, width, height = fit_image(width, height,
|
||||
60 if thumbnail else self.max_cover_width,
|
||||
80 if thumbnail else self.max_cover_height)
|
||||
if not scaled:
|
||||
return cover
|
||||
im = im.scaled(width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
ba = QByteArray()
|
||||
buf = QBuffer(ba)
|
||||
buf.open(QBuffer.WriteOnly)
|
||||
im.save(buf, 'PNG')
|
||||
return str(ba.data())
|
||||
im = im.resize((int(width), int(height)), PILImage.ANTIALIAS)
|
||||
of = cStringIO.StringIO()
|
||||
im.convert('RGB').save(of, 'JPEG')
|
||||
return of.getvalue()
|
||||
except Exception, err:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
@ -294,7 +294,7 @@ class LibraryServer(object):
|
||||
series = record[FIELD_MAP['series']]
|
||||
if series:
|
||||
extra.append('SERIES: %s [%s]<br />'%(series,
|
||||
fmt_sidx(record[FIELD_MAP['series_index']])))
|
||||
fmt_sidx(float(record[FIELD_MAP['series_index']]))))
|
||||
fmt = 'epub' if 'EPUB' in r else 'pdb'
|
||||
mimetype = guess_type('dummy.'+fmt)[0]
|
||||
books.append(self.STANZA_ENTRY.generate(
|
||||
@ -343,7 +343,7 @@ class LibraryServer(object):
|
||||
for record in items[start:start+num]:
|
||||
aus = record[2] if record[2] else __builtins__._('Unknown')
|
||||
authors = '|'.join([i.replace('|', ',') for i in aus.split(',')])
|
||||
r[10] = fmt_sidx(r[10])
|
||||
record[10] = fmt_sidx(float(record[10]))
|
||||
books.append(book.generate(r=record, authors=authors).render('xml').decode('utf-8'))
|
||||
updated = self.db.last_modified()
|
||||
|
||||
|
@ -271,7 +271,7 @@ get_all_removable_disks(struct tagDrives *g_drives)
|
||||
// Loop for all drives (MAX_DRIVES = 26)
|
||||
|
||||
|
||||
for(nLoopIndex = 0; nLoopIndex< MAX_DRIVES; nLoopIndex++)
|
||||
for(nLoopIndex = 0; nLoopIndex < MAX_DRIVES; nLoopIndex++)
|
||||
{
|
||||
// if a drive is present,
|
||||
if(dwDriveMask & 1)
|
||||
@ -306,6 +306,213 @@ get_all_removable_disks(struct tagDrives *g_drives)
|
||||
|
||||
}
|
||||
|
||||
static DEVINST
|
||||
GetDrivesDevInstByDeviceNumber(long DeviceNumber,
|
||||
UINT DriveType, char* szDosDeviceName)
|
||||
{
|
||||
GUID *guid;
|
||||
HDEVINFO hDevInfo;
|
||||
DWORD dwIndex, dwBytesReturned;
|
||||
BOOL bRet, IsFloppy;
|
||||
BYTE Buf[1024];
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
|
||||
long res;
|
||||
HANDLE hDrive;
|
||||
STORAGE_DEVICE_NUMBER sdn;
|
||||
|
||||
IsFloppy = (strstr(szDosDeviceName, "\\Floppy") != NULL); // is there a better way?
|
||||
|
||||
switch (DriveType) {
|
||||
case DRIVE_REMOVABLE:
|
||||
if ( IsFloppy ) {
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
|
||||
} else {
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
||||
}
|
||||
break;
|
||||
case DRIVE_FIXED:
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid drive type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get device interface info set handle
|
||||
// for all devices attached to system
|
||||
hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
|
||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
|
||||
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid handle value");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Retrieve a context structure for a device interface
|
||||
// of a device information set.
|
||||
dwIndex = 0;
|
||||
bRet = FALSE;
|
||||
|
||||
|
||||
pspdidd =
|
||||
(PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
|
||||
SP_DEVICE_INTERFACE_DATA spdid;
|
||||
SP_DEVINFO_DATA spdd;
|
||||
DWORD dwSize;
|
||||
|
||||
spdid.cbSize = sizeof(spdid);
|
||||
|
||||
while ( TRUE ) {
|
||||
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
|
||||
guid, dwIndex, &spdid);
|
||||
if ( !bRet ) {
|
||||
break;
|
||||
}
|
||||
|
||||
dwSize = 0;
|
||||
SetupDiGetDeviceInterfaceDetail(hDevInfo,
|
||||
&spdid, NULL, 0, &dwSize, NULL);
|
||||
|
||||
if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
|
||||
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
|
||||
|
||||
ZeroMemory((PVOID)&spdd, sizeof(spdd));
|
||||
spdd.cbSize = sizeof(spdd);
|
||||
|
||||
res =
|
||||
SetupDiGetDeviceInterfaceDetail(hDevInfo, &
|
||||
spdid, pspdidd,
|
||||
dwSize, &dwSize,
|
||||
&spdd);
|
||||
if ( res ) {
|
||||
hDrive = CreateFile(pspdidd->DevicePath,0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if ( hDrive != INVALID_HANDLE_VALUE ) {
|
||||
dwBytesReturned = 0;
|
||||
res = DeviceIoControl(hDrive,
|
||||
IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
||||
NULL, 0, &sdn, sizeof(sdn),
|
||||
&dwBytesReturned, NULL);
|
||||
if ( res ) {
|
||||
if ( DeviceNumber == (long)sdn.DeviceNumber ) {
|
||||
CloseHandle(hDrive);
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
return spdd.DevInst;
|
||||
}
|
||||
}
|
||||
CloseHandle(hDrive);
|
||||
}
|
||||
}
|
||||
}
|
||||
dwIndex++;
|
||||
}
|
||||
|
||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid device number");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static BOOL
|
||||
eject_drive_letter(char DriveLetter) {
|
||||
char szRootPath[4], szDevicePath[3], szVolumeAccessPath[7], szDosDeviceName[MAX_PATH];
|
||||
long DeviceNumber, res, tries;
|
||||
HANDLE hVolume;
|
||||
STORAGE_DEVICE_NUMBER sdn;
|
||||
DWORD dwBytesReturned;
|
||||
DEVINST DevInst;
|
||||
ULONG Status;
|
||||
ULONG ProblemNumber;
|
||||
PNP_VETO_TYPE VetoType;
|
||||
WCHAR VetoNameW[MAX_PATH];
|
||||
BOOL bSuccess;
|
||||
DEVINST DevInstParent;
|
||||
|
||||
szRootPath[0] = DriveLetter; szRootPath[1] = ':'; szRootPath[2] = '\\'; szRootPath[3] = (char)0;
|
||||
szDevicePath[0] = DriveLetter; szDevicePath[1] = ':'; szDevicePath[2] = (char)0;
|
||||
szVolumeAccessPath[0] = '\\'; szVolumeAccessPath[1] = '\\'; szVolumeAccessPath[2] = '.';
|
||||
szVolumeAccessPath[3] = '\\'; szVolumeAccessPath[4] = DriveLetter; szVolumeAccessPath[5] = ':';
|
||||
szVolumeAccessPath[6] = (char)0;
|
||||
|
||||
|
||||
DeviceNumber = -1;
|
||||
|
||||
hVolume = CreateFile(szVolumeAccessPath, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hVolume == INVALID_HANDLE_VALUE) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid handle value for drive letter");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dwBytesReturned = 0;
|
||||
res = DeviceIoControl(hVolume,
|
||||
IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
||||
NULL, 0, &sdn, sizeof(sdn),
|
||||
&dwBytesReturned, NULL);
|
||||
if ( res ) {
|
||||
DeviceNumber = sdn.DeviceNumber;
|
||||
}
|
||||
CloseHandle(hVolume);
|
||||
|
||||
if ( DeviceNumber == -1 ) {
|
||||
PyErr_SetString(PyExc_ValueError, "Can't find drive number");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
|
||||
if ( !res ) {
|
||||
PyErr_SetString(PyExc_ValueError, "Can't find dos device");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,
|
||||
DriveType, szDosDeviceName);
|
||||
if (DevInst == 0) return FALSE;
|
||||
|
||||
DevInstParent = 0;
|
||||
Status = 0;
|
||||
ProblemNumber = 0;
|
||||
PNP_VETO_TYPE VetoType;
|
||||
bSuccess = FALSE;
|
||||
|
||||
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
|
||||
|
||||
for ( tries = 0; tries < 3; tries++ ) {
|
||||
VetoNameW[0] = 0;
|
||||
|
||||
res = CM_Request_Device_EjectW(DevInstParent,
|
||||
&VetoType, VetoNameW, MAX_PATH, 0);
|
||||
|
||||
bSuccess = (res==CR_SUCCESS &&
|
||||
VetoType==PNP_VetoTypeUnknown);
|
||||
if ( bSuccess ) {
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep(500); // required to give the next tries a chance!
|
||||
}
|
||||
if (!bSuccess) PyErr_SetString(PyExc_ValueError, "Failed to eject drive after three tries");
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
winutil_eject_drive(PyObject *self, PyObject *args) {
|
||||
char DriveLetter;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "c", &DriveLetter)) return NULL;
|
||||
|
||||
if (!eject_drive_letter(DriveLetter)) return NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA
|
||||
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
|
||||
BOOL *iterate) {
|
||||
@ -697,6 +904,10 @@ is not present, current time as returned by localtime() is used. format must\n\
|
||||
be a unicode string. Returns unicode strings."
|
||||
},
|
||||
|
||||
{"eject_drive", winutil_eject_drive, METH_VARARGS,
|
||||
"eject_drive(drive_letter)\n\nEject a drive. Raises an exception on failure."
|
||||
},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user