Support for editing RTF metadata and documentation updates.

This commit is contained in:
Kovid Goyal 2007-06-02 19:42:53 +00:00
parent f119bb5994
commit 3bab77322e
5 changed files with 90 additions and 16 deletions

View File

@ -13,7 +13,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
''' E-book management software''' ''' E-book management software'''
__version__ = "0.3.44" __version__ = "0.3.45"
__docformat__ = "epytext" __docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -95,7 +95,8 @@ class TransferBuffer(list):
""" """
Return a string representation of this buffer. Return a string representation of this buffer.
Packets are represented as hex strings, in 2-byte pairs, S{<=} 16 bytes to a line. An ASCII representation is included. For example:: Packets are represented as hex strings, in 2-byte pairs, S{<=} 16 bytes to a line.
An ASCII representation is included. For example::
0700 0100 0000 0000 0000 0000 0c00 0000 ................ 0700 0100 0000 0000 0000 0000 0c00 0000 ................
0200 0000 0400 0000 4461 7461 ........Data 0200 0000 0400 0000 4461 7461 ........Data
""" """

View File

@ -13,8 +13,8 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
""" """
This package contains logic to read and write LRF files. The LRF file format is documented at U{http://www.sven.de/librie/Librie/LrfFormat}. This package contains logic to read and write LRF files.
At the time fo writing, this package only supports reading and writing LRF meat information. See L{meta}. The LRF file format is documented at U{http://www.sven.de/librie/Librie/LrfFormat}.
""" """
from optparse import OptionParser, OptionValueError from optparse import OptionParser, OptionValueError
@ -53,8 +53,8 @@ def option_parser(usage):
dest="title", help="Set the title. Default: filename.") dest="title", help="Set the title. Default: filename.")
metadata.add_option("-a", "--author", action="store", type="string", \ metadata.add_option("-a", "--author", action="store", type="string", \
dest="author", help="Set the author. Default: %default", default='Unknown') dest="author", help="Set the author. Default: %default", default='Unknown')
metadata.add_option("--freetext", action="store", type="string", \ metadata.add_option("--comment", action="store", type="string", \
dest="freetext", help="Set the comments.", default=' ') dest="freetext", help="Set the comment.", default=' ')
metadata.add_option("--category", action="store", type="string", \ metadata.add_option("--category", action="store", type="string", \
dest="category", help="Set the category", default=' ') dest="category", help="Set the category", default=' ')
metadata.add_option('--title-sort', action='store', default='', dest='title_sort', metadata.add_option('--title-sort', action='store', default='', dest='title_sort',

View File

@ -19,8 +19,26 @@ the L{libprs500.lrf.meta} module.
__docformat__ = "epytext" __docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
from optparse import OptionParser
from libprs500 import __version__ as VERSION
def get_parser(extension):
''' Return an option parser with the basic metadata options already setup'''
parser = OptionParser(version='libprs500 version: '+VERSION,
usage='''%prog [options] myfile.'''+extension)
parser.add_option("-t", "--title", action="store", type="string", \
dest="title", help="Set the book title")
parser.add_option("-a", "--authors", action="store", type="string", \
dest="authors", help="Set the authors", default=None)
parser.add_option("-c", "--category", action="store", type="string", \
dest="category", help="The category this book belongs"+\
" to. E.g.: History", default=None)
parser.add_option('--comment', dest='comment', default=None, action='store',
help='Set the comment')
return parser
class MetaInformation(object): class MetaInformation(object):
'''Convenient encapsulation of book metadata'''
def __init__(self, title, author): def __init__(self, title, author):
self.title = title self.title = title

View File

@ -13,11 +13,11 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
""" """
Read metadata from RTF files. Edit metadata in RTF files.
""" """
import re, cStringIO import re, cStringIO, sys
from libprs500.ebooks.metadata import MetaInformation from libprs500.ebooks.metadata import MetaInformation, get_parser
title_pat = re.compile(r'\{\\info.*?\{\\title(.*?)(?<!\\)\}', re.DOTALL) title_pat = re.compile(r'\{\\info.*?\{\\title(.*?)(?<!\\)\}', re.DOTALL)
author_pat = re.compile(r'\{\\info.*?\{\\author(.*?)(?<!\\)\}', re.DOTALL) author_pat = re.compile(r'\{\\info.*?\{\\author(.*?)(?<!\\)\}', re.DOTALL)
@ -27,7 +27,7 @@ category_pat = re.compile(r'\{\\info.*?\{\\category(.*?)(?<!\\)\}', re.DOTALL)
def get_document_info(stream): def get_document_info(stream):
""" """
Extract the \info block from an RTF file. Extract the \info block from an RTF file.
Return the info block as a stringa and the position in the file at which it Return the info block as a string and the position in the file at which it
starts. starts.
@param stream: File like object pointing to the RTF file. @param stream: File like object pointing to the RTF file.
""" """
@ -81,7 +81,7 @@ def get_metadata(stream):
author = author_match.group(1).strip() author = author_match.group(1).strip()
comment_match = comment_pat.search(block) comment_match = comment_pat.search(block)
if comment_match: if comment_match:
title = comment_match.group(1).strip() comment = comment_match.group(1).strip()
category_match = category_pat.search(block) category_match = category_pat.search(block)
if category_match: if category_match:
category = category_match.group(1).strip() category = category_match.group(1).strip()
@ -90,12 +90,67 @@ def get_metadata(stream):
mi.category = category mi.category = category
return mi return mi
def main(): def set_metadata(stream, options):
import sys '''
if len(sys.argv) != 2: Modify/add RTF metadata in stream
print >> sys.stderr, "Usage:", sys.argv[0], " mybook.rtf" @param options: Object with metadata attributes title, author, comment, category
'''
def add_metadata_item(src, name, val):
index = src.rindex('}')
return src[:index] + r'{\ '[:-1] + name + ' ' + val + '}}'
src, pos = get_document_info(stream)
olen = len(src)
base_pat = r'\{\\name(.*?)(?<!\\)\}'
title = options.title
if title != None:
title = title.encode('ascii', 'replace')
pat = re.compile(base_pat.replace('name', 'title'), re.DOTALL)
if pat.search(src):
src = pat.sub(r'{\\title ' + title + r'}', src)
else:
src = add_metadata_item(src, 'title', title)
comment = options.comment
if comment != None:
comment = comment.encode('ascii', 'replace')
pat = re.compile(base_pat.replace('name', 'subject'), re.DOTALL)
if pat.search(src):
src = pat.sub(r'{\\subject ' + comment + r'}', src)
else:
src = add_metadata_item(src, 'subject', comment)
author = options.authors
if author != None:
author = author.encode('ascii', 'replace')
pat = re.compile(base_pat.replace('name', 'author'), re.DOTALL)
if pat.search(src):
src = pat.sub(r'{\\author ' + author + r'}', src)
else:
src = add_metadata_item(src, 'author', author)
category = options.category
if category != None:
category = category.encode('ascii', 'replace')
pat = re.compile(base_pat.replace('name', 'category'), re.DOTALL)
if pat.search(src):
src = pat.sub(r'{\\category ' + category + r'}', src)
else:
src = add_metadata_item(src, 'category', category)
stream.seek(pos + olen)
after = stream.read()
stream.seek(pos)
stream.truncate()
stream.write(src)
stream.write(after)
def main(args=sys.argv):
parser = get_parser('rtf')
options, args = parser.parse_args(args)
if len(args) != 2:
parser.print_help()
sys.exit(1) sys.exit(1)
print get_metadata(open(sys.argv[1])) stream = open(args[1], 'r+b')
set_metadata(stream, options)
mi = get_metadata(stream)
return mi
if __name__ == '__main__': if __name__ == '__main__':
main() main()