feat: add ebook plugin for EPUB, FB2 and CBZ
This commit is contained in:
parent
e4fc6c0a59
commit
143c2b75ef
7 changed files with 272 additions and 17 deletions
119
tests/test_ebook.py
Normal file
119
tests/test_ebook.py
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import zipfile
|
||||
|
||||
import pytest
|
||||
|
||||
import orvanitag.orvani as orvani
|
||||
from orvanitag.orvani import OrvaniTag
|
||||
|
||||
CONTAINER = (
|
||||
'<?xml version="1.0"?><container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">'
|
||||
'<rootfiles><rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/></rootfiles></container>'
|
||||
)
|
||||
OPF = (
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
'<package xmlns="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="id">'
|
||||
'<metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:identifier id="id">x</dc:identifier>'
|
||||
'<dc:title>Book</dc:title><dc:subject>Fiction</dc:subject></metadata><manifest/><spine/></package>'
|
||||
)
|
||||
PREFIXED_OPF = (
|
||||
'<?xml version="1.0" encoding="UTF-8"?>'
|
||||
'<opf:package xmlns:opf="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="id">'
|
||||
'<opf:metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:title>Book</dc:title></opf:metadata></opf:package>'
|
||||
)
|
||||
FB2 = (
|
||||
'<?xml version="1.0" encoding="{encoding}"?>'
|
||||
'<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"><description><title-info>'
|
||||
'<keywords>космос</keywords><annotation><p>Аннотация</p></annotation></title-info></description>'
|
||||
'<body><p>Текст</p></body></FictionBook>'
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cwd(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
return tmp_path
|
||||
|
||||
|
||||
def make_epub(path, opf=OPF):
|
||||
with zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED) as z:
|
||||
z.writestr(zipfile.ZipInfo('mimetype'), 'application/epub+zip')
|
||||
z.writestr('META-INF/container.xml', CONTAINER)
|
||||
z.writestr('OEBPS/content.opf', opf)
|
||||
|
||||
|
||||
def make_cbz(path, comment=b''):
|
||||
with zipfile.ZipFile(path, 'w') as z:
|
||||
z.writestr('001.png', b'png')
|
||||
z.comment = comment
|
||||
|
||||
|
||||
def roundtrip(cwd, name, *tags):
|
||||
OrvaniTag().add(name, *tags)
|
||||
OrvaniTag().write_metadata(name, 'ebook')
|
||||
expected = (cwd / orvani.CONTEXT_FILE).read_text()
|
||||
(cwd / orvani.CONTEXT_FILE).unlink()
|
||||
OrvaniTag().read_metadata(name)
|
||||
assert (cwd / orvani.CONTEXT_FILE).read_text() == expected
|
||||
return expected
|
||||
|
||||
|
||||
def opf_of(path):
|
||||
with zipfile.ZipFile(path) as z:
|
||||
return z.read('OEBPS/content.opf').decode()
|
||||
|
||||
|
||||
def test_epub_roundtrip_keeps_book_metadata(cwd):
|
||||
make_epub(cwd / 'book.epub')
|
||||
line = roundtrip(cwd, 'book.epub', '+reading', '#scifi', 'R&B', '"quoted"', 'C:\\1')
|
||||
assert line == 'book.epub --- +reading #scifi R&B "quoted" C:\\1\n'
|
||||
opf = opf_of(cwd / 'book.epub')
|
||||
assert '<dc:title>Book</dc:title><dc:subject>Fiction</dc:subject>' in opf
|
||||
assert '<meta name="otag" content="+reading #scifi R&B "quoted" C:\\1"/></metadata>' in opf
|
||||
with zipfile.ZipFile(cwd / 'book.epub') as z:
|
||||
first = z.infolist()[0]
|
||||
assert first.filename == 'mimetype' and first.compress_type == zipfile.ZIP_STORED
|
||||
|
||||
|
||||
def test_epub_second_write_replaces_the_meta(cwd):
|
||||
make_epub(cwd / 'book.epub')
|
||||
o = OrvaniTag()
|
||||
o.add('book.epub', '#one')
|
||||
o.write_metadata('book.epub', 'ebook')
|
||||
o.add('book.epub', '#two')
|
||||
o.write_metadata('book.epub', 'ebook')
|
||||
opf = opf_of(cwd / 'book.epub')
|
||||
assert opf.count('name="otag"') == 1
|
||||
assert 'content="#one #two"' in opf
|
||||
|
||||
|
||||
def test_epub_with_prefixed_metadata(cwd):
|
||||
make_epub(cwd / 'book.epub', PREFIXED_OPF)
|
||||
roundtrip(cwd, 'book.epub', '#scifi')
|
||||
assert '<opf:meta name="otag" content="#scifi"/></opf:metadata>' in opf_of(cwd / 'book.epub')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('encoding', ['utf-8', 'windows-1251'])
|
||||
def test_fb2_roundtrip_keeps_encoding(cwd, encoding):
|
||||
(cwd / 'book.fb2').write_bytes(FB2.format(encoding=encoding).encode(encoding))
|
||||
line = roundtrip(cwd, 'book.fb2', '#фантастика', 'заметка')
|
||||
assert line == 'book.fb2 --- #фантастика заметка\n'
|
||||
text = (cwd / 'book.fb2').read_bytes().decode(encoding)
|
||||
assert '<keywords>космос</keywords><annotation><p>Аннотация</p></annotation></title-info>' in text
|
||||
assert '<custom-info info-type="otag">#фантастика заметка</custom-info></description>' in text
|
||||
|
||||
|
||||
def test_cbz_roundtrip_and_replacing_own_comment(cwd):
|
||||
make_cbz(cwd / 'comic.cbz', b'otag: #old')
|
||||
roundtrip(cwd, 'comic.cbz', '+series', '#manga')
|
||||
with zipfile.ZipFile(cwd / 'comic.cbz') as z:
|
||||
assert z.comment == b'otag: +series #manga'
|
||||
assert z.read('001.png') == b'png'
|
||||
|
||||
|
||||
def test_cbz_foreign_comment_is_kept(cwd):
|
||||
make_cbz(cwd / 'comic.cbz', b'{"ComicBookInfo/1.0": {}}')
|
||||
before = (cwd / 'comic.cbz').read_bytes()
|
||||
OrvaniTag().add('comic.cbz', '#manga')
|
||||
with pytest.raises(ValueError):
|
||||
OrvaniTag().write_metadata('comic.cbz', 'ebook')
|
||||
assert (cwd / 'comic.cbz').read_bytes() == before
|
||||
Loading…
Add table
Add a link
Reference in a new issue