mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
pdf2lrf
This commit is contained in:
parent
1a36564830
commit
8e8940f69e
@ -197,6 +197,9 @@ _check_symlinks_prescript()
|
||||
print 'Adding unrtf'
|
||||
os.link(os.path.expanduser('~/unrtf'), os.path.join(frameworks_dir, 'unrtf'))
|
||||
print
|
||||
print 'Adding pdftohtml'
|
||||
os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
|
||||
print
|
||||
print 'Installing prescipt'
|
||||
sf = [os.path.basename(s) for s in all_names]
|
||||
cs = BuildAPP.CHECK_SYMLINKS_PRESCRIPT % dict(dest_path=repr('/usr/bin'),
|
||||
|
1
setup.py
1
setup.py
@ -30,6 +30,7 @@ entry_points = {
|
||||
'rtf2lrf = libprs500.ebooks.lrf.rtf.convert_from:main',\
|
||||
'web2disk = libprs500.web.fetch.simple:main',\
|
||||
'web2lrf = libprs500.ebooks.lrf.web.convert_from:main',\
|
||||
'pdf2lrf = libprs500.ebooks.lrf.pdf.convert_from:main',\
|
||||
],
|
||||
'gui_scripts' : [ APPNAME+' = libprs500.gui.main:main']
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
''' E-book management software'''
|
||||
__version__ = "0.3.79"
|
||||
__version__ = "0.3.81"
|
||||
__docformat__ = "epytext"
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
__appname__ = 'libprs500'
|
||||
|
@ -255,11 +255,17 @@ class HTMLConverter(object):
|
||||
# Fix pdftohtml markup
|
||||
PDFTOHTML = [
|
||||
# Remove <hr> tags
|
||||
(re.compile(r'<hr.*?>', re.IGNORECASE), lambda match: ''),
|
||||
(re.compile(r'<hr.*?>', re.IGNORECASE), lambda match: '<span style="page-break-after:always"> </span>'),
|
||||
# Remove page numbers
|
||||
(re.compile(r'\d+<br>', re.IGNORECASE), lambda match: ''),
|
||||
# Remove <br> and replace <br><br> with <p>
|
||||
(re.compile(r'<br.*?>\s*<br.*?>', re.IGNORECASE), lambda match: '<p>'),
|
||||
(re.compile(r'(.{75,}?)<br.*?>', re.IGNORECASE),
|
||||
lambda match: match.group(1)),
|
||||
(re.compile(r'(.*)<br.*?>', re.IGNORECASE),
|
||||
lambda match: match.group() if re.match('<', match.group(1).lstrip()) or len(match.group(1)) < 40
|
||||
else match.group(1)),
|
||||
# Remove hyphenation
|
||||
(re.compile(r'-\n|-\n\r'), lambda match: ''),
|
||||
|
||||
]
|
||||
|
||||
class Link(object):
|
||||
|
@ -18,7 +18,7 @@ from subprocess import Popen, PIPE
|
||||
from libprs500.ebooks.lrf import option_parser as lrf_option_parser
|
||||
from libprs500.ebooks import ConversionError
|
||||
from libprs500.ebooks.lrf.html.convert_from import process_file
|
||||
from libprs500 import isosx
|
||||
from libprs500 import isosx, __appname__
|
||||
CLIT = 'clit'
|
||||
if isosx and hasattr(sys, 'frameworks_dir'):
|
||||
CLIT = os.path.join(sys.frameworks_dir, CLIT)
|
||||
@ -32,7 +32,7 @@ def option_parser():
|
||||
def generate_html(pathtolit):
|
||||
if not os.access(pathtolit, os.R_OK):
|
||||
raise ConversionError, 'Cannot read from ' + pathtolit
|
||||
tdir = mkdtemp(prefix='libprs500_lit2lrf_')
|
||||
tdir = mkdtemp(prefix=__appname__+'_')
|
||||
cmd = ' '.join([CLIT, '"'+pathtolit+'"', tdir])
|
||||
p = Popen(cmd, shell=True, stderr=PIPE)
|
||||
ret = p.wait()
|
||||
|
14
src/libprs500/ebooks/lrf/pdf/__init__.py
Normal file
14
src/libprs500/ebooks/lrf/pdf/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
73
src/libprs500/ebooks/lrf/pdf/convert_from.py
Normal file
73
src/libprs500/ebooks/lrf/pdf/convert_from.py
Normal file
@ -0,0 +1,73 @@
|
||||
## Copyright (C) 2007 Kovid Goyal kovid@kovidgoyal.net
|
||||
## This program is free software; you can redistribute it and/or modify
|
||||
## it under the terms of the GNU General Public License as published by
|
||||
## the Free Software Foundation; either version 2 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful,
|
||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along
|
||||
## with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
''''''
|
||||
|
||||
import sys, os, subprocess
|
||||
from libprs500 import isosx
|
||||
from libprs500.ebooks import ConversionError
|
||||
from libprs500.ptempfile import PersistentTemporaryFile
|
||||
from libprs500.ebooks.lrf import option_parser as lrf_option_parser
|
||||
from libprs500.ebooks.lrf.html.convert_from import process_file
|
||||
|
||||
PDFTOHTML = 'pdftohtml'
|
||||
if isosx and hasattr(sys, 'frameworks_dir'):
|
||||
PDFTOHTML = os.path.join(sys.frameworks_dir, PDFTOHTML)
|
||||
|
||||
|
||||
def generate_html(pathtopdf):
|
||||
'''
|
||||
Convert the pdf into html.
|
||||
@return: A closed PersistentTemporaryFile.
|
||||
'''
|
||||
if not os.access(pathtopdf, os.R_OK):
|
||||
raise ConversionError, 'Cannot read from ' + pathtopdf
|
||||
pf = PersistentTemporaryFile('.html')
|
||||
pf.close()
|
||||
cmd = PDFTOHTML + ' -noframes -p -nomerge "%s" "%s"'%(pathtopdf, pf.name)
|
||||
p = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE)
|
||||
ret = p.wait()
|
||||
if ret != 0:
|
||||
err = p.stderr.read()
|
||||
raise ConversionError, err
|
||||
return pf
|
||||
|
||||
def option_parser():
|
||||
return lrf_option_parser(
|
||||
'''Usage: %prog [options] mybook.pdf\n\n'''
|
||||
'''%prog converts mybook.pdf to mybook.lrf\n\n'''
|
||||
)
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
parser = option_parser()
|
||||
options, args = parser.parse_args(args)
|
||||
if len(args) != 2:
|
||||
parser.print_help()
|
||||
print
|
||||
print 'No pdf file specified'
|
||||
return 1
|
||||
pdf = os.path.abspath(os.path.expanduser(args[1]))
|
||||
htmlfile = generate_html(pdf)
|
||||
if not options.output:
|
||||
ext = '.lrs' if options.lrs else '.lrf'
|
||||
options.output = os.path.abspath(os.path.basename(os.path.splitext(args[1])[0]) + ext)
|
||||
else:
|
||||
options.output = os.path.abspath(options.output)
|
||||
options.pdftohtml = True
|
||||
process_file(htmlfile.name, options)
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -7,10 +7,6 @@ RC = images_rc.pyc
|
||||
%_rc.pyc : %.qrc %
|
||||
pyrcc4 $< > $*_rc.py
|
||||
python -c "import compiler; compiler.compileFile('$*_rc.py')"
|
||||
echo > $*_rc.py
|
||||
touch $*_rc.pyc
|
||||
|
||||
|
||||
|
||||
all : $(UI) $(RC)
|
||||
|
||||
|
@ -14,8 +14,8 @@
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
""" The GUI for libprs500. """
|
||||
import sys, os, re, StringIO, traceback
|
||||
from PyQt4.QtCore import QVariant, QSettings
|
||||
from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap
|
||||
from PyQt4.QtCore import QVariant, QSettings, QFileInfo
|
||||
from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider
|
||||
from libprs500 import __appname__ as APP_TITLE
|
||||
from libprs500 import __author__
|
||||
NONE = QVariant() #: Null value to return from the data function of item models
|
||||
@ -37,6 +37,8 @@ def error_dialog(parent, title, msg):
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_error.svg'))
|
||||
return d
|
||||
|
||||
def qstring_to_unicode(q):
|
||||
return unicode(q.toUtf8(), 'utf8')
|
||||
|
||||
def human_readable(size):
|
||||
""" Convert a size in bytes into a human readable form """
|
||||
@ -53,31 +55,111 @@ def human_readable(size):
|
||||
size = size[:size.find(".")+2]
|
||||
return size + " " + suffix
|
||||
|
||||
def choose_files(window, dialog, title, filetype='',
|
||||
extensions=[], all_files=True):
|
||||
|
||||
class FileIconProvider(QFileIconProvider):
|
||||
|
||||
ICONS = {
|
||||
'default' : 'unknown',
|
||||
'dir' : 'dir',
|
||||
'zero' : 'zero',
|
||||
'jpeg' : 'jpeg',
|
||||
'jpg' : 'jpeg',
|
||||
'gif' : 'gif',
|
||||
'png' : 'png',
|
||||
'bmp' : 'bmp',
|
||||
'svg' : 'svg',
|
||||
'html' : 'html',
|
||||
'lit' : 'lit',
|
||||
'lrf' : 'lrf',
|
||||
'lrx' : 'lrx',
|
||||
'pdf' : 'pdf',
|
||||
'rar' : 'rar',
|
||||
'zip' : 'zip',
|
||||
'txt' : 'txt',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
QFileIconProvider.__init__(self)
|
||||
self.icons = {}
|
||||
for key in self.__class__.ICONS.keys():
|
||||
self.icons[key] = ':/images/mimetypes/'+self.__class__.ICONS[key]+'.svg'
|
||||
|
||||
|
||||
def pixmap(self, fileinfo):
|
||||
key = 'default'
|
||||
icons = self.icons
|
||||
if fileinfo.isSymlink():
|
||||
if not fileinfo.exists():
|
||||
return icons['zero']
|
||||
fileinfo = QFileInfo(fileinfo.readLink())
|
||||
if fileinfo.isDir():
|
||||
key = 'dir'
|
||||
else:
|
||||
ext = qstring_to_unicode(fileinfo.extension(True)).lower()
|
||||
key = [i for i in icons.keys() if i in ext]
|
||||
key = key[0] if key else 'default'
|
||||
if key:
|
||||
key = key[0]
|
||||
candidate = icons[key]
|
||||
if isinstance(candidate, QPixmap):
|
||||
return candidate
|
||||
pixmap = QPixmap(candidate)
|
||||
icons[key] = pixmap
|
||||
return pixmap
|
||||
|
||||
file_icon_provider = None
|
||||
|
||||
class FileDialog(QFileDialog):
|
||||
def __init__(self, title='Choose Files',
|
||||
filters=[],
|
||||
add_all_files_filter=True,
|
||||
parent=None,
|
||||
modal = True,
|
||||
name = '',
|
||||
mode = QFileDialog.ExistingFiles,
|
||||
):
|
||||
QFileDialog.__init__(self, parent)
|
||||
self.setModal(modal)
|
||||
global file_icon_provider
|
||||
if not file_icon_provider:
|
||||
file_icon_provider = FileIconProvider()
|
||||
if not self.iconProvider() is file_icon_provider:
|
||||
self.setIconProvider(file_icon_provider)
|
||||
|
||||
settings = QSettings()
|
||||
_dir = settings.value(name, QVariant(os.path.expanduser("~"))).toString()
|
||||
self.setDirectory(_dir)
|
||||
ftext = ''
|
||||
if filters:
|
||||
for filter in filters:
|
||||
text, extensions = filter
|
||||
extensions = ['.'+i if not i.startswith('.') else i for i in extensions]
|
||||
ftext += '%s (%s);;'%(text, ' '.join(extensions))
|
||||
if add_all_files_filter or not ftext:
|
||||
ftext += 'All files (*)'
|
||||
self.setFilters(ftext)
|
||||
self.setWindowTitle(title)
|
||||
|
||||
def get_files(self):
|
||||
self.exec_()
|
||||
return tuple(os.path.abspath(qstring_to_unicode(i)) for i in self.selectedFiles())
|
||||
|
||||
|
||||
def choose_files(window, name, title,
|
||||
filters=[], all_files=True, select_only_single_file=False):
|
||||
'''
|
||||
Ask user to choose a bunch of files.
|
||||
@param dialog: Unique gialog name used to store the opened directory
|
||||
@param name: Unique dialog name used to store the opened directory
|
||||
@param title: Title to show in dialogs titlebar
|
||||
@param filetype: What types of files is this dialog choosing
|
||||
@params extensions: list of allowable extension
|
||||
@params all_files: If True show all files
|
||||
@param filters: list of allowable extensions. Each element of the list
|
||||
must be a 2-tuple with first element a string describing
|
||||
the type of files to be filtered and second element a list
|
||||
of extensions.
|
||||
@param all_files: If True add All files to filters.
|
||||
@param select_only_single_file: If True only one file can be selected
|
||||
'''
|
||||
settings = QSettings()
|
||||
_dir = settings.value(dialog, QVariant(os.path.expanduser("~"))).toString()
|
||||
books = []
|
||||
extensions = ['*.'+i for i in extensions]
|
||||
if extensions:
|
||||
filter = filetype + ' (' + ' '.join(extensions) + ')'
|
||||
if all_files:
|
||||
filter += ';;All files (*)'
|
||||
else:
|
||||
filter = 'All files (*)'
|
||||
files = QFileDialog.getOpenFileNames(window, title, _dir, filter)
|
||||
for file in files:
|
||||
file = unicode(file.toUtf8(), 'utf8')
|
||||
books.append(os.path.abspath(file))
|
||||
if books:
|
||||
settings.setValue(dialog, QVariant(os.path.dirname(books[0])))
|
||||
return books
|
||||
|
||||
mode = QFileDialog.ExistingFile if select_only_single_file else QFileDialog.ExistingFiles
|
||||
fd = FileDialog(title=title, name=name, filters=filters,
|
||||
parent=window, add_all_files_filter=all_files, mode=mode,
|
||||
)
|
||||
return fd.get_files()
|
@ -14,5 +14,13 @@
|
||||
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
'''Various dialogs used in the GUI'''
|
||||
|
||||
from PyQt4.QtCore import QObject
|
||||
from PyQt4.QtGui import QDialog
|
||||
|
||||
|
||||
class ModalDialog(QObject):
|
||||
def __init__(self, window):
|
||||
QObject.__init__(self, window)
|
||||
self.dialog = QDialog(window)
|
||||
self.accept = self.dialog.accept
|
||||
self.reject = self.dialog.reject
|
||||
self.window = window
|
@ -20,9 +20,11 @@ import os
|
||||
|
||||
from PyQt4.QtCore import Qt, SIGNAL
|
||||
from PyQt4.Qt import QObject, QPixmap, QListWidgetItem, QErrorMessage, \
|
||||
QVariant, QSettings, QFileDialog, QDialog
|
||||
QVariant, QSettings, QFileDialog
|
||||
|
||||
|
||||
from libprs500.gui2 import qstring_to_unicode, error_dialog
|
||||
from libprs500.gui2.dialogs import ModalDialog
|
||||
from libprs500.gui2.dialogs.metadata_single_ui import Ui_MetadataSingleDialog
|
||||
|
||||
class Format(QListWidgetItem):
|
||||
@ -32,7 +34,7 @@ class Format(QListWidgetItem):
|
||||
QListWidgetItem.__init__(self, ext.upper(), parent, \
|
||||
QListWidgetItem.UserType)
|
||||
|
||||
class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
class MetadataSingleDialog(Ui_MetadataSingleDialog, ModalDialog):
|
||||
|
||||
def select_cover(self, checked):
|
||||
settings = QSettings()
|
||||
@ -40,25 +42,27 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
QVariant(os.path.expanduser("~"))).toString()
|
||||
_file = str(QFileDialog.getOpenFileName(self.parent, \
|
||||
"Choose cover for " + str(self.title.text()), _dir, \
|
||||
"Images (*.png *.gif *.jpeg *.jpg);;All files (*)"))
|
||||
"Images (*.png *.gif *.jpeg *.jpg *.svg);;All files (*)"))
|
||||
if len(_file):
|
||||
_file = os.path.abspath(_file)
|
||||
settings.setValue("change cover dir", \
|
||||
QVariant(os.path.dirname(_file)))
|
||||
if not os.access(_file, os.R_OK):
|
||||
QErrorMessage(self.parent).showMessage("You do not have "+\
|
||||
"permission to read the file: " + _file)
|
||||
d = error_dialog(self.window, 'Cannot read',
|
||||
'You do not have permission to read the file: ' + _file)
|
||||
d.exec_()
|
||||
return
|
||||
cf, cover = None, None
|
||||
try:
|
||||
cf = open(_file, "rb")
|
||||
cover = cf.read()
|
||||
except IOError, e:
|
||||
QErrorMessage(self.parent).showMessage("There was an error"+\
|
||||
" reading from file: " + _file + "\n"+str(e))
|
||||
d = error_dialog(self.window, 'Error reading file',
|
||||
"<p>There was an error reading from file: <br /><b>" + _file + "</b></p><br />"+str(e))
|
||||
d.exec_()
|
||||
if cover:
|
||||
pix = QPixmap()
|
||||
pix.loadFromData(cover, "", Qt.AutoColor)
|
||||
pix.loadFromData(cover)
|
||||
if pix.isNull():
|
||||
QErrorMessage(self.parent).showMessage(_file + \
|
||||
" is not a valid picture")
|
||||
@ -83,7 +87,7 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
for _file in files:
|
||||
_file = os.path.abspath(_file)
|
||||
if not os.access(_file, os.R_OK):
|
||||
QErrorMessage(self.parent).showMessage("You do not have "+\
|
||||
QErrorMessage(self.window).showMessage("You do not have "+\
|
||||
"permission to read the file: " + _file)
|
||||
continue
|
||||
ext = os.path.splitext(_file)[1].lower()
|
||||
@ -124,15 +128,17 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
self.db.remove_format(self.id, ext)
|
||||
self.db.update_max_size(self.id)
|
||||
|
||||
def __init__(self, parent, row, db):
|
||||
def __init__(self, window, row, db, slot):
|
||||
Ui_MetadataSingleDialog.__init__(self)
|
||||
QDialog.__init__(parent)
|
||||
self.setupUi(parent)
|
||||
ModalDialog.__init__(self, window)
|
||||
self.setupUi(self.dialog)
|
||||
self.splitter.setStretchFactor(100, 1)
|
||||
self.db = db
|
||||
self.id = db.id(row)
|
||||
self.cover_data = None
|
||||
self.formats_changed = False
|
||||
self.cover_changed = False
|
||||
self.slot = slot
|
||||
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \
|
||||
self.select_cover)
|
||||
QObject.connect(self.add_format_button, SIGNAL("clicked(bool)"), \
|
||||
@ -140,10 +146,8 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
QObject.connect(self.remove_format_button, SIGNAL("clicked(bool)"), \
|
||||
self.remove_format)
|
||||
QObject.connect(self.button_box, SIGNAL("accepted()"), \
|
||||
self.sync_formats)
|
||||
self.sync)
|
||||
|
||||
data = self.db.get_row_by_id(self.id, \
|
||||
["title","authors","rating","publisher","tags","comments"])
|
||||
self.title.setText(db.title(row))
|
||||
au = self.db.authors(row)
|
||||
self.authors.setText(au if au else '')
|
||||
@ -154,7 +158,8 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
rating = self.db.rating(row)
|
||||
if rating > 0:
|
||||
self.rating.setValue(rating)
|
||||
self.comments.setPlainText(data["comments"] if data["comments"] else "")
|
||||
comments = self.db.comments(row)
|
||||
self.comments.setPlainText(comments if comments else '')
|
||||
cover = self.db.cover(row)
|
||||
if cover:
|
||||
pm = QPixmap()
|
||||
@ -166,3 +171,17 @@ class EditBookDialog(Ui_MetadataSingleDialog, QDialog):
|
||||
# if not ext:
|
||||
# ext = "Unknown"
|
||||
# Format(self.formats, ext)
|
||||
|
||||
self.dialog.exec_()
|
||||
|
||||
def sync(self):
|
||||
if self.formats_changed:
|
||||
self.sync_formats()
|
||||
title = qstring_to_unicode(self.title.text())
|
||||
self.db.set_title(self.id, title)
|
||||
au = qstring_to_unicode(self.authors.text()).split(',')
|
||||
self.db.set_authors(self.id, au)
|
||||
self.slot()
|
||||
|
||||
def reject(self):
|
||||
self.rejected = True
|
||||
|
@ -494,22 +494,6 @@
|
||||
<include location="../images.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>button_box</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MetadataSingleDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>button_box</sender>
|
||||
<signal>accepted()</signal>
|
||||
@ -526,5 +510,21 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>button_box</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MetadataSingleDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
@ -10,22 +10,27 @@
|
||||
<file>images/jobs.svg</file>
|
||||
<file alias="library" >images/library.png</file>
|
||||
<file>images/list_remove.svg</file>
|
||||
<file>images/mimetypes/bmp.svg</file>
|
||||
<file>images/mimetypes/dir.svg</file>
|
||||
<file>images/mimetypes/gif.svg</file>
|
||||
<file>images/mimetypes/html.svg</file>
|
||||
<file>images/mimetypes/jpeg.svg</file>
|
||||
<file>images/mimetypes/lit.svg</file>
|
||||
<file>images/mimetypes/lrf.svg</file>
|
||||
<file>images/mimetypes/lrx.svg</file>
|
||||
<file>images/mimetypes/pdf.svg</file>
|
||||
<file>images/mimetypes/png.svg</file>
|
||||
<file>images/mimetypes/rar.svg</file>
|
||||
<file>images/mimetypes/rtf.svg</file>
|
||||
<file>images/mimetypes/svg.svg</file>
|
||||
<file>images/mimetypes/txt.svg</file>
|
||||
<file>images/mimetypes/unknown.svg</file>
|
||||
<file>images/mimetypes/zero.svg</file>
|
||||
<file>images/mimetypes/zip.svg</file>
|
||||
<file>images/plus.svg</file>
|
||||
<file>images/reader.svg</file>
|
||||
<file>images/sd.svg</file>
|
||||
<file>images/sync.svg</file>
|
||||
<file>images/trash.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/" >
|
||||
<file>images/mimetypes/format_html.svg</file>
|
||||
<file>images/mimetypes/format_lit.svg</file>
|
||||
<file>images/mimetypes/format_lrf.svg</file>
|
||||
<file>images/mimetypes/format_lrx.svg</file>
|
||||
<file>images/mimetypes/format_pdf.svg</file>
|
||||
<file>images/mimetypes/format_rar.svg</file>
|
||||
<file>images/mimetypes/format_rtf.svg</file>
|
||||
<file>images/mimetypes/format_txt.svg</file>
|
||||
<file>images/mimetypes/format_unknown.svg</file>
|
||||
<file>images/mimetypes/format_zip.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -28,6 +28,7 @@ from libprs500.gui2.main_ui import Ui_MainWindow
|
||||
from libprs500.gui2.device import DeviceDetector, DeviceManager
|
||||
from libprs500.gui2.status import StatusBar
|
||||
from libprs500.gui2.jobs import JobManager, JobException
|
||||
from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
|
||||
|
||||
class Main(QObject, Ui_MainWindow):
|
||||
|
||||
@ -194,8 +195,9 @@ class Main(QObject, Ui_MainWindow):
|
||||
'''
|
||||
Add books from the local filesystem to either the library or the device.
|
||||
'''
|
||||
books = choose_files(self.window, 'add books dialog dir', 'Select books', 'Books',
|
||||
extensions=['lrf', 'lrx', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'html', 'xhtml', 'epub'])
|
||||
books = choose_files(self.window, 'add books dialog dir', 'Select books',
|
||||
filters=[('Books', ['lrf', 'lrx', 'rar', 'zip',
|
||||
'rtf', 'lit', 'txt', 'htm', 'html', 'xhtml', 'epub',])])
|
||||
if not books:
|
||||
return
|
||||
on_card = False if self.stack.currentIndex() != 2 else True
|
||||
@ -309,9 +311,21 @@ class Main(QObject, Ui_MainWindow):
|
||||
############################### Edit metadata ##############################
|
||||
def edit_metadata(self, checked):
|
||||
'''
|
||||
Edit metadata of selected books in library or on device.
|
||||
Edit metadata of selected books in library individually.
|
||||
'''
|
||||
pass
|
||||
rows = self.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
return
|
||||
changed = False
|
||||
def cs():
|
||||
changed = True
|
||||
for row in rows:
|
||||
MetadataSingleDialog(self.window, row.row(), self.library_view.model().db, cs)
|
||||
|
||||
if changed:
|
||||
self.library_view.model().resort()
|
||||
self.library_view.model().research()
|
||||
|
||||
############################################################################
|
||||
|
||||
############################# Syncing to device#############################
|
||||
|
@ -626,6 +626,7 @@ class LibraryDatabase(object):
|
||||
return self.data[index][1]
|
||||
|
||||
def authors(self, index):
|
||||
''' Authors as a comman separated list or None'''
|
||||
return self.data[index][2]
|
||||
|
||||
def publisher(self, index):
|
||||
@ -641,6 +642,7 @@ class LibraryDatabase(object):
|
||||
return self.data[index][6]
|
||||
|
||||
def cover(self, index):
|
||||
'''Cover as a data string or None'''
|
||||
id = self.id(index)
|
||||
matches = self.conn.execute('SELECT data from covers where id=?', (id,)).fetchall()
|
||||
if not matches:
|
||||
@ -651,6 +653,7 @@ class LibraryDatabase(object):
|
||||
return None
|
||||
|
||||
def tags(self, index):
|
||||
'''tags as a comman separated list or None'''
|
||||
id = self.id(index)
|
||||
matches = self.conn.execute('SELECT concat(name) FROM tags WHERE tags.id IN (SELECT tag from books_tags_link WHERE book=?)', (id,)).fetchall()
|
||||
if not matches:
|
||||
@ -658,6 +661,7 @@ class LibraryDatabase(object):
|
||||
return matches[0][0]
|
||||
|
||||
def comments(self, index):
|
||||
'''Comments as string or None'''
|
||||
id = self.id(index)
|
||||
matches = self.conn.execute('SELECT text FROM comments WHERE book=?', (id,)).fetchall()
|
||||
if not matches:
|
||||
@ -678,7 +682,9 @@ class LibraryDatabase(object):
|
||||
|
||||
|
||||
def set(self, row, column, val):
|
||||
''' Convenience method for setting the title, authors, publisher or rating '''
|
||||
'''
|
||||
Convenience method for setting the title, authors, publisher or rating
|
||||
'''
|
||||
id = self.data[row][0]
|
||||
cols = {'title' : 1, 'authors': 2, 'publisher': 3, 'rating':4}
|
||||
col = cols[column]
|
||||
@ -699,10 +705,14 @@ class LibraryDatabase(object):
|
||||
self.set_rating(id, val)
|
||||
|
||||
def set_authors(self, id, authors):
|
||||
'''
|
||||
@param authors: A list of authors.
|
||||
'''
|
||||
self.conn.execute('DELETE FROM books_authors_link WHERE book=?',(id,))
|
||||
for a in authors:
|
||||
if not a:
|
||||
continue
|
||||
a = a.strip()
|
||||
author = self.conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone()
|
||||
if author:
|
||||
aid = author[0]
|
||||
|
@ -80,6 +80,7 @@ def setup_completion():
|
||||
f.write(opts_and_exts('txt2lrf', txtop, ['txt']))
|
||||
f.write(opts_and_exts('lit2lrf', htmlop, ['lit']))
|
||||
f.write(opts_and_exts('rtf2lrf', htmlop, ['rtf']))
|
||||
f.write(opts_and_exts('pdf2lrf', htmlop, ['pdf']))
|
||||
f.write(opts_and_exts('lrf-meta', metaop, ['lrf']))
|
||||
f.write('''
|
||||
_prs500_ls()
|
||||
|
@ -57,6 +57,7 @@ Var MUI_TEMP
|
||||
!define LIBUNRAR_DIR "C:\Program Files\UnrarDLL"
|
||||
!define CLIT "C:\clit\clit.exe"
|
||||
!define UNRTF "C:\unrtf\unrtf.exe"
|
||||
!define PDFTOHTML "C:\pdftohtml\pdftohtml.exe"
|
||||
|
||||
;------------------------------------------------------------------------------------------------------
|
||||
;General
|
||||
@ -126,6 +127,7 @@ Section "libprs500" Seclibprs500
|
||||
File /r "${PY2EXE_DIR}\*"
|
||||
File "${CLIT}"
|
||||
File "${UNRTF}"
|
||||
File "${PDFTOHTML}"
|
||||
|
||||
SetOutPath "$INSTDIR\driver"
|
||||
File "${LIBUSB_DIR}\*.dll"
|
||||
|
Loading…
x
Reference in New Issue
Block a user