Create a gist now

Instantly share code, notes, and snippets.

@te223 /bindao.py
Last active Dec 27, 2015

What would you like to do?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
r'''
青空文庫のテキストファイルを結合するためのpython スクリプト。
python > 2.7 が必要。 python3 では動きません。
使い方は、$ python bindao.py -h 及び、 $ python bindao.py -H
'''
import sys, os, re
import zipfile, tempfile
_version = "0.8.0"
_program="bindao.py"
#_isdebug = True
_isdebug = False
_ioenc = "utf-8"
######## Convenience Functions #############################
def expand_path(path):
return os.path.expandvars( os.path.expanduser(path) )
def is_emptyline(line):
return re.match(r'^[\r\n]*$', line)
def isterminal(f):
return hasattr(f, "isatty") and f.isatty()
def find(foo, seq):
for s in seq:
if foo(s): return s
return None
def U(s):
if isinstance(s, str): return s.decode("utf-8", "replace")
return unicode(s)
def MS(s): return U(s).encode("ms932", "replace")
def escMS(s): return re.escape(MS(s))
def oprif(port, fmt, *args):
if not args: port.write(U(fmt).encode(_ioenc, "replace"))
else:
ustr = U(fmt) % tuple(
U(a) if isinstance(a, str) else a for a in args)
port.write(ustr.encode(_ioenc, "replace"))
def prif(fmt, *args): oprif(sys.stdout, fmt, *args)
def eprif(fmt, *args): oprif(sys.stderr, fmt, *args)
# for zipfile.ZipFile() in python2.6
class FileCtx(object):
def __init__(self, fobj): self.fobj = fobj
def __enter__(self): return self.fobj
def __exit__(self, exc_type, exc_value, traceback):
if not (self.fobj == sys.stdin):
# print " %s will close" % self.fobj # for debug
self.fobj.close()
# print u" %s did close" % self.fobj # for debug
return False # throw exception
# examples:
# >>> fill("abc", 10) #-> 'abc '
# >>> fill("abc", 10, "-") #-> 'abc-------'
# >>> fill([1,2,3],5 ) #-> [1, 2, 3, None, None]
# >>> fill([1,2,3],5, [0]) #-> [1, 2, 3, 0, 0]
# >>> fill((1,2,3), 6) #-> (1, 2, 3, None, None, None)
# >>> fill((1,2,3), 6, (0,)) #-> (1, 2, 3, 0, 0, 0)
def fill(seq, length, e=None):
if( e is None):
if isinstance(seq, basestring): e = " "
elif isinstance(seq, list): e = [None]
elif isinstance(seq, tuple): e = (None,)
for i in xrange(len(seq), length): seq = seq + e
return seq
######## End of Convenience Functions ######################
# unicode でパターンを与えて、ms932 byte列の正規表現パターンを得る関数
# eformat(fmt, arg ...)
# fmt には、正規表現オペレータ文字を ascii で指定
# arg... で与えた文字は、正規表現エスケープされ、ms932のバイト列に
# 変換される。
# Shift jis のバイト列のままで正規表現をかけるための苦肉の策...
# 全てutf-8に変換してから処理するのでもいいのかもしれない。でも、
# ms932 <-> utf# のマッピングで文字化けを起こしてまうかな、と思ったので…
#
# examples:
# p = eformat(r'%s\s*(%s|%s|%s)%s', "表示起動", "大", "中", "小", "見出し")
# rx = re.compile(p)
# m = rx.search(MS("abc表示起動 中見出しxyz"))
# print m.group().decode("ms932") #=> 表示起動 中見出し
# print m.group(1).decode("ms932") #=> 中
def eformat(fmt, *args):
return (
fmt % tuple( re.escape( U(s).encode("ms932", "replace")) for s in args )
)
# rep_midasi の utf-8 版 (デバッグ用)
# examples:
# s = u"start[#ここから大見出し]q[#大見出し]abcd[#「○○」は中見出し]dayo[#「○○」は大見出し]aaa[#中見出し終わり]rrr[#ここで中見出し終わり]"
# print rep_midasi_u(s)
# たぶん、[#「[#ここから大見出し]」は中見出し] なんてのはバグる
def rep_midasi_u(line):
def replace(m):
s = m.group(0)
ns = u""
if m.group(1) == u"": ns = u""
return line[m.start(0):m.start(1)] + ns + line[m.end(1):m.end(0)]
line = re.sub(ur'[#「.*?」は(?:同行|窓)?(大|中)見出し]', replace, line)
line = re.sub(ur'[#(?:同行|窓)?(大|中)見出し(終わり)?', replace, line)
line = re.sub(ur'[#ここ(?:から|で)(大|中)見出し(終わり)?', replace, line)
return line
# examples:
# s = MS( u"start[#ここから大見出し]q[#大見出し]abcd[#「○○」は中見出し]dayo[#「○○」は大見出し]aaa[#中見出し終わり]rrr[#ここで中見出し終わり]" )
# print s.decode("ms932")
# print rep_midasi(s).decode("ms932")
# たぶん、[#「[#ここから大見出し]」は中見出し] なんてのはバグる
def rep_midasi(line):
def replace(m):
s = m.group(0)
ns = MS(u"")
if m.group(1) == MS(u""): ns = MS(u"")
return line[m.start(0):m.start(1)] + ns + line[m.end(1):m.end(0)]
#line = re.sub(ur'[#「.*?」は(?:同行|窓)?(大|中)見出し]', replace, line)
p = eformat('%s.*?%s(?:%s|%s)?(%s|%s)%s',
"[#「", "」は", "同行", "", "","", "見出し]")
line = re.sub(p, replace, line)
#line = re.sub(ur'[#(?:同行|窓)?(大|中)見出し(終わり)?]', replace, line)
p = eformat('%s(?:%s|%s)?(%s|%s)%s(%s)?%s',
"[#", "同行", "", "", "", "見出し", "終わり", "")
line = re.sub(p, replace, line)
#line = re.sub(ur'[#ここ(?:から|で)(大|中)見出し(終わり)?]', replace, line)
p = eformat("%s(?:%s|%s)(%s|%s)%s(%s)?%s",
"[#ここ", "から", "", "", "", "見出し", "終わり", "")
line = re.sub(p, replace, line)
return line
def srch_midasi(uline, report = None):
if not report:
report = {u"":0, u"":0, u"":0}
for p in [ ur'[#「.*?」は(?:同行|窓)?(大||小)見出し]',
ur'[#(?:同行|窓)?(大||小)見出し\s*',
ur'[#ここから(大||小)見出し\s*']:
for m in re.finditer(p, uline):
midashi = m.group(1)
if midashi in report:
report[midashi] = report[midashi] + 1
else:
eprif("ERROR: program error in srch_midasi - %s\n", midashi)
return report
class UngetableReader(object):
def __init__(self, port):
self.port = port
self.unget_buf = []
def nextline(self):
if self.unget_buf:
return self.unget_buf.pop(0)
else:
return self.port.readline()
def eachline(self):
while True:
data = self.nextline()
if data: yield(data)
else: break
def unget(self, data): self.unget_buf.append(data)
class TextReader(object):
def __init__(self, filename):
self.filename = filename
self.headers = []
def read(self, cb_header, cb_body):
with open(self.filename) as f:
reader = UngetableReader(f)
self.read_header(reader, cb_header, cb_body)
def read_header(self, reader, cb_header, cb_body):
for line in reader.eachline():
if is_emptyline(line):
return self.read_note(reader, cb_body)
if cb_header:
if not cb_header(line): break
return
def read_note(self, reader, cb_body):
# 注記のセパレーター(--------------- )の読み込み
line1 = reader.nextline()
uline = line1.decode("ms932", "replace").strip()
#print "line1=", uline
if not re.match(r'^----+$', uline):
reader.unget(line1)
return self.read_body(reader, cb_body)
# 注記のtag 【テキスト中に現れる記号について】の読み込み
line2 = reader.nextline()
uline = line2.decode("ms932", "replace").strip()
#print "line2=", uline
if not re.match(ur'^\s*【テ.スト中.*記号.*', uline, re.U):
eprif(u"WARNING: 記号注釈タグがありません\n")
reader.unget(line1)
reader.unget(line2)
return self.read_body(reader, cb_body)
# 記号注釈をスキップ
for line in reader.eachline():
# 全角空白も strip されちゃう
uline = line.decode("ms932", "replace").strip()
if re.match(r'^----+$', uline) :
eline = reader.nextline()
if not is_emptyline(eline): reader.unget(eline)
return self.read_body(reader, cb_body)
#print "記号注釈:", uline
return
def read_body(self, reader, cb_body):
#print "--- body ---"
if cb_body:
for line in reader.eachline():
#sys.stdout.write(line.decode("ms932", "replace"))
if not cb_body(line): break
# Zip から text ファイルを探して、その ZipInfo を返す。
# zfile は、zipfile名を示すstrか、または ZipFile object
def find_ziptext(zfile):
def find(z):
for zinfo in z.infolist():
if re.search( r'\.txt$', zinfo.filename, re.I):
return zinfo
return None
if isinstance(zfile, zipfile.ZipFile): return find(zfile)
else:
with FileCtx(zipfile.ZipFile(zfile, "r")) as zp:
return find(zp)
class ZipTextReader(TextReader):
#def __init__(self, filename):
# TextReader.__init__(self, filename)
def read(self, cb_header, cb_body):
with FileCtx(zipfile.ZipFile(self.filename, "r")) as zp:
zinfo = find_ziptext(zp)
if zinfo is not None:
with FileCtx(zp.open(zinfo, "r")) as f:
reader = UngetableReader(f)
self.read_header(reader, cb_header, cb_body)
class Checker(object):
def __init__(self, filename):
self.filename = filename
self.iszip = zipfile.is_zipfile(self.filename)
self.reset()
def reset(self):
self.body_count = 0
self.headers = []
self.midashi = {}
def check(self):
self.reset()
tr = (ZipTextReader if self.iszip else TextReader)(self.filename)
tr.read(self.mk_headerhd(), self.mk_bodyhd())
def mk_headerhd(self):
def handler(line):
self.headers.append( line.strip().decode("ms932", "replace") )
return True
return handler
def mk_bodyhd(self):
def handler(line):
self.body_count += 1
#sys.stdout.write("%04d:" % self.body_count + line.decode("ms932", "replace"))
uline = line.decode("ms932", "replace")
self.midashi = srch_midasi(uline, self.midashi)
return True
return handler
def is_replace_midashi(self):
if self.midashi.get(u"", 0) > 0:
if self.midashi.get(u"",0) > 0:
if self.midashi.get(u"", 0) <= 0:
#大分類があり、中分類があり、小分類がない場合は変換
return True
else:
#大分類があり、中分類がない場合は、大->中 の変換
return True
return False
def writeWork(outport, work):
#見出しのありなしをチェック
chk = Checker(work.filename)
chk.check()
is_replace_midashi = chk.is_replace_midashi()
outport.write( MS(u'[#改ページ]\r\n') )
title = work.title or u"タイトル不明"
s = u"%s[#「%s」は大見出し]\r\n" % (title, title)
outport.write( MS(s) )
subtitle = work.subtitle
if subtitle:
s = u"[#2字下げ]" + subtitle + u"\r\n"
outport.write( MS(s) )
author = work.author
if author:
s = u"[#地から3字上げ]" + author + u"\r\n"
outport.write( MS(s) )
outport.write("\r\n")
def body_handler(line):
if is_replace_midashi:
line = rep_midasi(line)
outport.write( line )
return True
tr = (ZipTextReader if work.iszip else TextReader)(work.filename)
tr.read(None, body_handler)
def writeWork_plain(outport, work):
outport.write( MS(u'[#改ページ]\r\n') )
def handler(line):
outport.write( line )
return True
tr = (ZipTextReader if work.iszip else TextReader)(work.filename)
tr.read(handler, handler)
def bind(bindfile, bindtop, worklist, isplain=False):
with open(bindfile, "wb") as outport:
if bindtop.title:
outport.write( MS(bindtop.title) + "\r\n" )
if bindtop.subtitle:
outport.write( MS(bindtop.subtitle) + "\r\n" )
if bindtop.author:
outport.write( MS(bindtop.author) + "\r\n" )
outport.write("\r\n")
writer = writeWork
if isplain: writer = writeWork_plain
for work in worklist:
writer(outport, work)
class TempfileCtx(object):
def __init__(self):
(fd, self.tmpfile) = tempfile.mkstemp(".txt", "bindao")
os.close(fd) # Fix me
if _isdebug: prif("tmpfile = %s\n", self.tmpfile)
def __enter__(self): return self.tmpfile
def __exit__(self, exc_type, exc_value, traceback):
os.unlink(self.tmpfile)
return False # throw exception
def bindzip(bindname, bindtop, worklist, others=[], isplain=False):
with FileCtx(zipfile.ZipFile(bindname.encode("utf-8", "replace") + ".zip",
"w", zipfile.ZIP_DEFLATED)) as outzp:
# write bind text
with TempfileCtx() as tfile:
bind(tfile, bindtop, worklist, isplain)
outzp.write(tfile, bindname.encode("utf-8", "replace") + ".txt")
# wite worklist's zipfile exception text file
for work in worklist:
if work.iszip:
with FileCtx(zipfile.ZipFile(work.filename, "r") ) as zp:
txtinfo = find_ziptext(zp)
for zinfo in zp.infolist():
if zinfo is not txtinfo:
bytes = zp.read(zinfo)
outzp.writestr(zinfo, bytes)
#prif("mkzip: write %s#%s\n", work.filename, zinfo.filename) # debug
# write others
for fname in others:
outzp.write(fname, os.path.basename(fname))
class Work(object):
def __init__(self, filename, order):
self.filename = filename
self.order = order
(self.title, self.subtitle, self.author) = (None, None, None)
if self.filename is None: self.iszip = None
else:
self.iszip = zipfile.is_zipfile(self.filename)
def ziptext(self):
"zipアーカイブ中のテキストファイルを ZipInfoで返す"
if self.iszip: return find_ziptext(self.filename)
else: return None
def text_filename(self):
ztext = self.ziptext()
if ztext: return ztext.filename
elif self.iszip: return None
return self.filename
def textname(self):
fname = self.text_filename()
if fname is not None:
return os.path.basename(fname)
return None
def set_default_by_checker(self, sub2title=False):
"sub2title: 副題(2行目)を表題とする"
if(os.path.isfile(self.filename)):
(self.title, self.subtitle, self.author) = (None, None, None)
c = Checker(self.filename)
c.check()
if len(c.headers) == 2:
(self.title, self.author) = c.headers
elif len(c.headers) == 3:
if sub2title:
(_dmy, self.title, self.author) = c.headers
else:
(self.title, self.subtitle, self.author) = c.headers
class CDoc:
def __init__(self, name, pattern, usage, desc):
(self.name, self.pattern, self.usage, self.desc) = (
U(name), U(pattern), U(usage), U(desc))
if isinstance(self.pattern, basestring):
self.pattern = re.compile(self.pattern)
def display(self, indent=0):
sp = u" " * indent
prif(u"%s%s\n%s Usage: %s\n", sp, self.name, sp, self.usage)
for line in self.desc.split("\n"):
prif("%s %s\n", sp, line)
class CDocList:
def __init__(self, *docs): self.doclist = docs
def find(self, s):
return find(lambda d: d.pattern.match(s), self.doclist)
_cmddocs = CDocList(
CDoc("show", "sh.*", "sh{ow} {all}",
u''' 現在の情報を表示する。
Topレベルでは合本の情報を表示します。
editコマンドで構成作品の編集中ならば、各構成ファイルの情報を表示します。
all を指定すると、合本ファイルと全ての構成ファイルの情報を表示します。'''),
CDoc("title", "ti.*", "ti{tle} {表題}",
u''' Topレベルならば、合本の表題を設定します。
editで構成作品の編集中ならば、構成作品の表題を設定します。
表題の指定を省略すると、現在の表題を表示します。'''),
CDoc("author", "au.*", "au{thor} {著者名}",
u''' Topレベルならば、合本の著者名を設定します。
editで構成作品の編集中ならば、構成作品の著者名を設定します。
著者名の指定を省略すると、現在の著者名を表示します。'''),
CDoc("subtitle", "sub.*", "sub{title} {副題}",
u''' Topレベルならば、合本の副題を設定します。
editで構成作品の編集中ならば、構成作品の副題を設定します。
副題の指定を省略すると、現在の副題を表示します。'''),
CDoc("unset", "(unset|del).*", "unset t|a|s",
u''' Topレベルならば、合本の 表題|副題|著者名 を無効にします。
editコマンドで各構成作品の編集中ならば、その構成作品の表題|副題|著者名
を無効にします。
(tを指定:表題の削除 aを指定:著者名の削除 sを指定:副題の削除)'''),
CDoc("edit", "(?!echo)e.*", "e{dit} 合本の構成ファイル名又は構成番号",
u''' 指定した構成作品の、表題、副題、著者名などを編集するモードになり、
プロンプトが構成ファイル名に変わります。'''),
CDoc("top", "(to|ret|up|\\^).*", "to{p}",
u''' 合本の本体の、表題、副題、著者名などを編集するモードになり、
プロンプトが、`Top> ' に変わります。'''),
CDoc("check", "ch.*", "ch{eck}",
u''' 合本を作成するための情報が足りているかを確認します'''),
CDoc("bind", "bind$", "bind {ファイル名}",
u''' 各構成ファイルを結合して、ファイル名で合本します。
ファイル名省略時は、bind.txt。
ファイルエクステンションを省くと .txt が自動で付きます。'''),
CDoc("bindzip", "bindzip$", "bindzip {合本名} {with 画像ファイルなど...}",
u'''\
各構成ファイルを結合して合本テキストを作成し、with で指定した画像
ファイルなどと一緒にzipでアーカイブします。
zip形式の構成ファイルについては、そのzip内の画像ファイルは自動で出力
アーカイブに組み込まれます。
`合本名` -- 合本となるzipアーカイブファイル名(.zipは必要ありません)
zip 内の合本テキストファイルは、`合本名`.txt になります。
合本名省略時は `bind`''' ),
CDoc("help", "(h|\\?).*", "h{elp} {command}",
u'''コマンドの使い方を表示します。
command を省略すると、全てのコマンドを表示します。'''),
CDoc("#", "#.*", "#コメントテキスト", "コメント"),
CDoc("quit", "q.*", "q{uit}", "終了"),
)
def cmdhelp(cmd=None):
if cmd:
doc = _cmddocs.find(cmd)
if doc: doc.display()
else: prif(u"No help for %s\n", cmd)
else:
for doc in _cmddocs.doclist:
doc.display(); prif("\n")
def main(worklist,
sub2title=False, noauthor=False, isplain=False):
bindtop = Work(None, 0)
current_work = bindtop
inport = UngetableReader(sys.stdin)
for w in worklist:
w.set_default_by_checker(sub2title)
if noauthor: w.author = None
def tty(): return isterminal(inport.port)
def prompt():
if(tty()):
if current_work == bindtop: pstr = u"Top"
else:
pstr = os.path.splitext(current_work.textname() or u"Unknown")[0]
sys.stdout.write(pstr + u"> ")
sys.stdout.flush()
def find_work(fname):
if fname is None: return None
def comp(wk):
tname = wk.textname()
return fname in (tname, os.path.splitext(tname)[0],
wk.text_filename(), wk.filename)
retwork = find(lambda w: comp(w), worklist)
if not retwork:
try: retwork = worklist[ int(fname) - 1 ]
except (ValueError, IndexError) : pass
return retwork
def show_title_etc(work, indent, *args):
sp = u" " * indent
for key in args:
if key == u"title":
fmt = u"合本時の表題: %s\n"
if work == bindtop: fmt = u"合本の表題: %s\n"
prif(sp + fmt, work.title or u"★未設定★")
elif key == u"author":
fmt = u"合本時の著者: %s\n"
if work == bindtop: fmt = u"合本の著者: %s\n"
prif(sp + fmt, work.author or u"★未設定★")
elif key == u"subtitle":
fmt = u"合本時の副題: %s\n"
if work == bindtop: fmt = u"合本の副題: %s\n"
prif(sp + fmt, work.subtitle or u"-未設定-")
def show_top(show_works=False):
show_title_etc(bindtop, 0, u"title", u"author", u"subtitle")
if show_works:
for w in worklist: show_work(w, 0)
else:
for w in worklist: show_work_filename(w, 0)
def show_work_filename(work, indent=0):
sp = u" " * indent
fname = work.filename
if work.iszip:
fname = u"%s 内の %s" % (fname, (work.text_filename() or u""))
prif(sp + u"構成ファイル(%d): %s\n", work.order, fname)
def show_work(work, indent=0):
sp = u" " * indent
show_work_filename(work, indent)
show_title_etc(work, indent+2, u"title", u"author", u"subtitle")
c = Checker(work.filename)
c.check()
if c.headers:
prif(sp + u" 元テキストの表題、著者名など:\n")
for h in c.headers: prif(sp + u" " + h + "\n")
else: prif(sp + u" 何もありません\n")
prif(sp + u" 元テキストの本文の行数:%d\n", c.body_count)
#if c.midashi.get(u"小"): prif(u" ★小見出しがあります★\n")
prif(sp + u" 元テキストの大見出し:%s 中見出し:%s 小見出し:%s\n",
*( (u"%d" % (c.midashi.get(k,0))) if c.midashi.get(k,0) else u"なし"
for k in (u"", u"", u"")))
if not isplain and c.is_replace_midashi():
prif(sp + u" ☆合本時には、各見出しを変換します☆\n")
elif c.midashi.get(u"") and c.midashi.get(u"") and c.midashi.get(u""):
prif(sp +
u" ★大、中、小の全ての見出しがありますので、合本時には大見出しが重複します★\n")
prif("\n");
def precheck():
msg = []
# 合本の表題、著者が指定されているか?
if not bindtop.title: msg.append(u"合本の表題が未指定です")
if not bindtop.author: msg.append(u"合本の著者名が未指定です")
if not isplain:
for w in worklist:
fname = os.path.basename(w.filename)
if not w.title: msg.append(u"構成作品 %s の表題が未指定です" % fname)
if not noauthor:
if not w.author: msg.append(u"構成作品 %s の著者名が未指定です" % fname)
return msg
if tty(): inport.unget("show\n")
#for line in iter(sys.stdin.readline, ""):
for line in inport.eachline():
try:
if isinstance(line, str): line = line.decode(_ioenc, "replace")
(top, rest) = fill( line.strip().split(None,1), 2, [u""])
top = top.lower()
if top.startswith("#"):
prompt()
continue
elif top.startswith("echo"):
prif("%s\n", rest)
elif top.startswith("e"): # edit command
if not rest: cmdhelp("edit")
else:
work = find_work(rest)
if work:
current_work = work
#inport.unget("show\n")
if tty(): show_work(current_work)
else: eprif(u"ERROR: %s は、構成ファイル外です\n", rest)
elif find(lambda p: top.startswith(p), ("to", "ret", "up", "^")): # return top command
current_work = bindtop
if tty(): show_top()
elif (not top) or ( top.startswith("sh")): # show command
if top or tty():
if rest.startswith("all"): show_top(True)
elif current_work == bindtop: show_top()
else: show_work(current_work)
elif top.startswith("ti"): # title command
if rest: current_work.title = rest
if tty() or (not rest): show_title_etc(current_work, 0, "title")
elif top.startswith("au"): # author command
if rest: current_work.author = rest
if tty() or (not rest): show_title_etc(current_work, 0, "author")
elif top.startswith("sub"): # subtitle command
if rest: current_work.subtitle = rest
if tty() or (not rest): show_title_etc(current_work, 0, "subtitle")
elif find(lambda p: top.startswith(p), ("unset", "del")): # unset command
if( rest.startswith("t") ):
current_work.title = None
show_title_etc(current_work, 0, "title")
elif( rest.startswith("a") ):
current_work.author = None
show_title_etc(current_work, 0, "author")
elif( rest.startswith("s") ):
current_work.subtitle = None
show_title_etc(current_work, 0, "subtitle")
else:
cmdhelp("unset")
elif top.startswith(u"ch"): # check command
emsg = precheck()
if emsg:
for e in emsg: prif("%s\n", e)
else: prif("OK\n")
elif top == u"bind":
if not bindtop.title:
eprif(u"ERROR: 合本の表題が未指定です\n")
else:
bindfile = rest or "bind.txt"
if not os.path.splitext(bindfile)[1]:
bindfile = bindfile + ".txt"
bind(bindfile, bindtop, worklist, isplain)
if tty(): prif(u"OK: %s を出力しました\n", bindfile)
elif top == u"bindzip":
if not bindtop.title:
eprif(u"ERROR: 合本の表題が未指定です\n")
else:
bindname = u"bind"
others = []
if rest:
restlist = rest.split()
id_with = -1
try: id_with = restlist.index("with")
except ValueError:pass
if id_with == 1:
bindname = os.path.splitext(os.path.basename(restlist[0]))[0]
others = restlist[2:]
elif id_with == 0:
others = restlist[1:]
elif(id_with == -1):
bindname = os.path.splitext(os.path.basename(restlist[0]))[0]
else: bindname = None
#prif("bindname=%s others=%s\n", bindname, ",".join(others)) # debug
if bindname is None or re.match(r'''^\.+''', bindname):
cmdhelp("bindzip")
else:
bindzip(bindname, bindtop, worklist, others=others, isplain=isplain)
if tty(): prif(u"OK: %s を出力しました\n", bindname + ".zip")
elif top.startswith("q"): break
elif find(lambda p: top.startswith(p), ("h", "?")):
if rest: cmdhelp(rest.split()[0])
else: cmdhelp()
else:
eprif(u"ERROR: Illegal command - %s\n", line)
except Exception as ex:
if _isdebug:
import traceback
tblist = traceback.format_tb(sys.exc_info()[2])
for tbstr in tblist: sys.stderr.write(tbstr)
eprif("ERROR: %s\n", str(ex))
prompt()
if __name__ == '__main__':
def filecheck(fname):
if not os.path.exists(fname):
eprif("ERROR: ファイル '%s' が見当たりませんので無視します。\n", fname)
return False
elif not os.path.isfile(fname):
eprif("ERROR: ファイル '%s' は普通のファイルじゃないみたいなので無視します。\n", fname)
return False
else: return True
def usage():
progname = os.path.basename(sys.argv[0])
prif(ur'''青空文庫のテキストファイルを結合するスクリプト。
使用例:
青空文庫から、3つの zip ファイルをダウンロードして、それらを、
AozoraEpub3 と kindlegenを使って、一つのmobi に変換する場合の例です。
# まずは、青空文庫から zip ファイルをダウンロードする
$ curl -O http://www.aozora.gr.jp/cards/xxxx/files/some_textfile1.zip
$ curl -O http://www.aozora.gr.jp/cards/xxxx/files/some_textfile2.zip
$ curl -O http://www.aozora.gr.jp/cards/xxxx/files/some_textfile3.zip
# some_textfile[1-3] を結合して bind.zip を作る
$ %s some_textfile.zip some_textfile2.zip some_textfile3.zip
Top> help
コマンドの説明などが表示される...
Top> title 適当な表題
Top> author 作者の名前
Top> show all
Top> bindzip
OK: bind.zip を出力しました
Top> quit
# AozoraEpub3 を使って、epub ファイルの作成
$ java -jar AozoraEpub3.jar
(端末設定 で kindle-PW を選択
表題: 本文内 「表題→著者名」を選択し、「先頭が発行者」のチェックを外す。
目次設定の「目次(NCX)階層化」のチェックをいれる、他はデフォルトのまま。
bind.zipをドラッグアンドドロップ)
# mobi 変換
$ kindlegen .........
Usage: %s {OPTIONS} text_or_zipfiles ...
text_or_zipfiles:
合本される個々の作品ファイル (zip または 普通のtextファイル)
OPTIONS:
-sub: 個々の作品ファイルの副題を表題とする
(たいていは、シリーズ物を合本するに使用)
-noauthor:
個々の作品ファイルの著者名を省く。
(たいていは、同じ作者のシリーズ物を合本する時に使用)
-p : 階層的な見出しにしない
(デフォルトでは、構成作品の表題を「大見出し」に設定し、
作品の本文中に現れる、大見出しを中見出しに、そして、
中見出しを小見出しに変換する処理を行います。
-p オプションを指定すると、この変換処理を行いません。)
-ioenc ENC : 端末入出力のエンコード (defaultは utf-8)
-ms: -ioenc cp932 と同じ
-V : バージョン番号の表示
-h : %s の 使い方を表示
-H : コマンドヘルプを表示
''' , progname, progname, progname)
exit(1)
isplain = False ; sub2title = False; noauthor = False;
workfiles = []
arglist = sys.argv[1:]
try:
while arglist:
arg = arglist.pop(0)
if arg.startswith("-"):
if arg == "-p":
isplain = True
elif arg == "-sub":
sub2title = True
elif arg.startswith("-noa"):
noauthor = True
elif arg.startswith("-H"):
cmdhelp()
exit(1)
elif arg == "-V":
prif("%s %s\n", _program, _version)
exit(0)
elif arg == "-ioenc":
_ioenc = arglist.pop(0)
elif arg == "-ms":
_ioenc = "cp932"
else:
usage()
else:
workfiles.append(arg)
except IndexError:
usage()
if not workfiles:
usage()
worklist = []
order = 1
for fname in workfiles:
if filecheck(fname):
work = Work(fname, order)
if work.iszip and (work.ziptext() is None):
eprif("ERROR: アーカイブ '%s' の中にテキストファイルがないようですので無視します\n",
fname)
else:
worklist.append(work)
order += 1
if worklist:
main(worklist, sub2title=sub2title, noauthor=noauthor, isplain=isplain)
else:
eprif("処理するファイルがなかったので、何もしないで終わります。\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment