aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md20
-rwxr-xr-xepy.py361
-rw-r--r--setup.py2
3 files changed, 286 insertions, 97 deletions
diff --git a/README.md b/README.md
index 9ecd6d2..ce69b27 100644
--- a/README.md
+++ b/README.md
@@ -19,13 +19,15 @@ This is just a fork of my own [epr](https://github.com/wustho/epr) with these ex
- Inline formats: **bold** and _italic_ (depend on terminal and font capability. Italic only supported in python>=3.7)
- Text-to-Speech (with additional setup, read [below](#text-to-speech))
- [Double Spread](#double-spread)
+- Seamless (disabled by default, read [below](#reading-tips-using-epy))
## Note on `v2021.10.23` and beyond
There happened major refactoring for `epy` in version `v2021.10.23` which harness
a lot of new stuffs in python standard libraries starting from `python>=3.7`, so
`epy` won't be compatible with older python version and won't be backward compatible
-with older `epy` version. And if you decide to install this version you might lose
+with older `epy` configuration and reading states.
+So if you decide to install this version, you will lose
your reading progress with older `epy`.
## Installation
@@ -51,15 +53,23 @@ your reading progress with older `epy`.
## Reading Tips Using Epy
When reading using `epy` you might occasionally find triple asteriks `***`.
-That means you reach the end of some section in your ebook and the next line (right after those three asteriks, which is in new section) will start at the top of the page.
-This might be disorienting, so the best way to get seamless reading experience is by using next-page control (`space`, `l` or `Right`) instead of next-line control (`j` or `Down`).
+That means you reach the end of some section in your ebook
+and the next line (right after those three asteriks, which is in new section)
+will start at the top of the page.
+This might be disorienting, so the best way to get seamless reading experience
+is by using next-page control (`space`, `l` or `Right`)
+instead of next-line control (`j` or `Down`).
+
+If you really want to get seamless reading experience, you can set `SeamlessBetweenChapters`
+to `true` in configuration file. But it has its drawback with more memory usage, that's why
+it's disabled by default.
## Configuration File
Config file is available in json format which is located at:
-- Linux: `~/.config/epy/config.json` or `~/.epy/config.json`
-- Windows: `%USERPROFILE%\.epy\config.json`
+- Linux: `~/.config/epy/configuration.json` or `~/.epy/configuration.json`
+- Windows: `%USERPROFILE%\.epy\configuration.json`
Although, there are not many stuffs to configure.
diff --git a/epy.py b/epy.py
index c6ea471..b49d7ce 100755
--- a/epy.py
+++ b/epy.py
@@ -14,7 +14,7 @@ Options:
"""
-__version__ = "2021.10.25"
+__version__ = "2021.10.29"
__license__ = "GPL-3.0"
__author__ = "Benawi Adha"
__email__ = "benawiadha@gmail.com"
@@ -35,10 +35,11 @@ import subprocess
import sys
import tempfile
import textwrap
+import uuid
import xml.etree.ElementTree as ET
import zipfile
-from typing import Optional, Union, Tuple, List, Mapping, Any
+from typing import Optional, Union, Sequence, Tuple, List, Mapping, Set, Any
from dataclasses import dataclass
from difflib import SequenceMatcher as SM
from enum import Enum
@@ -54,7 +55,6 @@ try:
except ModuleNotFoundError:
MOBI_SUPPORT = False
-
# add image viewers here
# sorted by most widely used
VIEWER_PRESET_LIST = (
@@ -82,9 +82,22 @@ class DoubleSpreadPadding(Enum):
@dataclass(frozen=True)
class ReadingState:
- content_index: int = 0
- textwidth: int = 80
- row: int = 0
+ """
+ Data model for reading state.
+
+ `row` has to be explicitly assigned with value
+ because Seamless feature needs it to adjust from
+ relative (to book's content index) row to absolute
+ (to book's entire content) row.
+
+ `rel_pctg` and `section` default to None and if
+ either of them is assigned with value, then it
+ will be overriding the `row` value.
+ """
+
+ content_index: int
+ textwidth: int
+ row: int
rel_pctg: Optional[float] = None
section: Optional[str] = None
@@ -187,6 +200,7 @@ class Settings:
DarkColorBG: int = 235
LightColorFG: int = 238
LightColorBG: int = 253
+ SeamlessBetweenChapters: bool = False
@dataclass(frozen=True)
@@ -197,8 +211,8 @@ class CfgDefaultKeymaps:
PageDown: str = "l"
# HalfScreenUp: str = "h"
# HalfScreenDown: str
- NextChapter: str = "n"
- PrevChapter: str = "p"
+ NextChapter: str = "L"
+ PrevChapter: str = "H"
BeginningOfCh: str = "g"
EndOfCh: str = "G"
Shrink: str = "-"
@@ -287,8 +301,8 @@ class Epub:
self.root_filepath: str
self.root_dirpath: str
self.toc_path: str
- self.contents: Tuple[str] = ()
- self.toc_entries: Tuple[TocEntry] = ()
+ self.contents: Tuple[str, ...] = tuple()
+ self.toc_entries: Tuple[TocEntry, ...] = tuple()
def get_meta(self) -> Tuple[Tuple[str, str], ...]:
meta: List[Tuple[str, str]] = []
@@ -706,7 +720,7 @@ class HTMLtoLines(HTMLParser):
self.idpref.add(len(self.text) - 1)
def get_structured_text(
- self, textwidth: Optional[int] = 0
+ self, textwidth: Optional[int] = 0, starting_line: int = 0
) -> Union[Tuple[str, ...], TextStructure]:
text: List[str] = []
images: Mapping[int, str] = dict() # {line_num: path/in/zip}
@@ -753,12 +767,14 @@ class HTMLtoLines(HTMLParser):
# # i = i.replace(" (#" + findsect.group() + ") ", " "*(5+len(findsect.group())))
# sect[findsect.group()] = len(text)
if n in self.sectsindex.keys():
- sect[self.sectsindex[n]] = len(text)
+ sect[self.sectsindex[n]] = starting_line + len(text)
if n in self.idhead:
# text += [i.rjust(textwidth // 2 + len(i) // 2)] + [""]
text += [i.center(textwidth)] + [""]
formatting += [
- InlineStyle(row=j, col=0, n_letters=len(text[j]), attr=curses.A_BOLD)
+ InlineStyle(
+ row=starting_line + j, col=0, n_letters=len(text[j]), attr=curses.A_BOLD
+ )
for j in range(startline, len(text))
]
elif n in self.idinde:
@@ -773,11 +789,14 @@ class HTMLtoLines(HTMLParser):
wraptmp += [j for j in textwrap.wrap(line, textwidth - 6)]
text += [" " + j for j in wraptmp] + [""]
elif n in self.idimgs:
- images[len(text)] = self.imgs[n]
+ images[starting_line + len(text)] = self.imgs[n]
text += [i.center(textwidth)]
formatting += [
InlineStyle(
- row=len(text) - 1, col=0, n_letters=len(text[-1]), attr=curses.A_BOLD
+ row=starting_line + len(text) - 1,
+ col=0,
+ n_letters=len(text[-1]),
+ attr=curses.A_BOLD,
)
]
text += [""]
@@ -806,7 +825,7 @@ class HTMLtoLines(HTMLParser):
if tmp_start[0] == tmp_end[0]:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=tmp_end[1] - tmp_start[1],
attr=curses.A_ITALIC,
@@ -815,7 +834,7 @@ class HTMLtoLines(HTMLParser):
elif tmp_start[0] == tmp_end[0] - 1:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=len(text[tmp_start[0]]) - tmp_start[1] + 1,
attr=curses.A_ITALIC,
@@ -823,14 +842,17 @@ class HTMLtoLines(HTMLParser):
)
formatting.append(
InlineStyle(
- row=tmp_end[0], col=0, n_letters=tmp_end[1], attr=curses.A_ITALIC
+ row=starting_line + tmp_end[0],
+ col=0,
+ n_letters=tmp_end[1],
+ attr=curses.A_ITALIC,
)
)
# elif tmp_start[0]-tmp_end[1] > 1:
else:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=len(text[tmp_start[0]]) - tmp_start[1] + 1,
attr=curses.A_ITALIC,
@@ -838,11 +860,19 @@ class HTMLtoLines(HTMLParser):
)
for l in range(tmp_start[0] + 1, tmp_end[0]):
formatting.append(
- InlineStyle(row=l, col=0, n_letters=len(text[l]), attr=curses.A_ITALIC)
+ InlineStyle(
+ row=starting_line + l,
+ col=0,
+ n_letters=len(text[l]),
+ attr=curses.A_ITALIC,
+ )
)
formatting.append(
InlineStyle(
- row=tmp_end[0], col=0, n_letters=tmp_end[1], attr=curses.A_ITALIC
+ row=starting_line + tmp_end[0],
+ col=0,
+ n_letters=tmp_end[1],
+ attr=curses.A_ITALIC,
)
)
tmp_filtered = [j for j in tmpbold if j[0] == n]
@@ -865,7 +895,7 @@ class HTMLtoLines(HTMLParser):
if tmp_start[0] == tmp_end[0]:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=tmp_end[1] - tmp_start[1],
attr=curses.A_BOLD,
@@ -874,20 +904,25 @@ class HTMLtoLines(HTMLParser):
elif tmp_start[0] == tmp_end[0] - 1:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=len(text[tmp_start[0]]) - tmp_start[1] + 1,
attr=curses.A_BOLD,
)
)
formatting.append(
- InlineStyle(row=tmp_end[0], col=0, n_letters=tmp_end[1], attr=curses.A_BOLD)
+ InlineStyle(
+ row=starting_line + tmp_end[0],
+ col=0,
+ n_letters=tmp_end[1],
+ attr=curses.A_BOLD,
+ )
)
# elif tmp_start[0]-tmp_end[1] > 1:
else:
formatting.append(
InlineStyle(
- row=tmp_start[0],
+ row=starting_line + tmp_start[0],
col=tmp_start[1],
n_letters=len(text[tmp_start[0]]) - tmp_start[1] + 1,
attr=curses.A_BOLD,
@@ -895,10 +930,20 @@ class HTMLtoLines(HTMLParser):
)
for l in range(tmp_start[0] + 1, tmp_end[0]):
formatting.append(
- InlineStyle(row=l, col=0, n_letters=len(text[l]), attr=curses.A_BOLD)
+ InlineStyle(
+ row=starting_line + l,
+ col=0,
+ n_letters=len(text[l]),
+ attr=curses.A_BOLD,
+ )
)
formatting.append(
- InlineStyle(row=tmp_end[0], col=0, n_letters=tmp_end[1], attr=curses.A_BOLD)
+ InlineStyle(
+ row=starting_line + tmp_end[0],
+ col=0,
+ n_letters=tmp_end[1],
+ attr=curses.A_BOLD,
+ )
)
# chapter suffix
@@ -1071,8 +1116,8 @@ class State(AppData):
if result:
result = dict(result)
del result["filepath"]
- return ReadingState(**result)
- return ReadingState()
+ return ReadingState(**result, section=None)
+ return ReadingState(content_index=0, textwidth=80, row=0, rel_pctg=None, section=None)
finally:
conn.close()
@@ -1333,6 +1378,71 @@ class InfiniBoard:
)
+def parse_html(
+ html_src: str,
+ *,
+ textwidth: Optional[int] = None,
+ section_ids: Optional[Set[str]] = None,
+ starting_line: int = 0,
+) -> Union[Tuple[str, ...], TextStructure]:
+ """
+ Parse html string into TextStructure
+
+ :param html_src: html str to parse
+ :param textwidth: textwidth to count max length of returned TextStructure
+ if None given, sequence of text as paragraph is returned
+ :param section_ids: set of section ids to look for inside html tag attr
+ :return: Tuple[str, ...] if textwidth not given else TextStructure
+ """
+ if not section_ids:
+ section_ids = set()
+
+ parser = HTMLtoLines(section_ids)
+ # try:
+ parser.feed(html_src)
+ parser.close()
+ # except:
+ # pass
+
+ return parser.get_structured_text(textwidth, starting_line)
+
+
+def merge_text_structures(
+ text_structure_first: TextStructure, text_structure_second: TextStructure
+) -> TextStructure:
+ return TextStructure(
+ text_lines=text_structure_first.text_lines + text_structure_second.text_lines,
+ image_maps={**text_structure_first.image_maps, **text_structure_second.image_maps},
+ section_rows={**text_structure_first.section_rows, **text_structure_second.section_rows},
+ formatting=text_structure_first.formatting + text_structure_second.formatting,
+ )
+
+
+def construct_relative_reading_state(
+ abs_reading_state: ReadingState, totlines_per_content: Sequence[int]
+) -> ReadingState:
+ """
+ :param abs_reading_state: ReadingState absolute to whole book when Setting.Seamless==True
+ :param totlines_per_content: sequence of total lines per book content
+ :return: new ReadingState relative to per content of the book
+ """
+ cumulative_contents_lines = 0
+ all_contents_lines = sum(totlines_per_content)
+ for n, content_lines in enumerate(totlines_per_content):
+ cumulative_contents_lines += content_lines
+ if cumulative_contents_lines > abs_reading_state.row:
+ return ReadingState(
+ content_index=n,
+ textwidth=abs_reading_state.textwidth,
+ row=abs_reading_state.row - cumulative_contents_lines + content_lines,
+ rel_pctg=abs_reading_state.rel_pctg
+ - ((cumulative_contents_lines - content_lines) / all_contents_lines)
+ if abs_reading_state.rel_pctg
+ else None,
+ section=abs_reading_state.section,
+ )
+
+
def get_ebook_obj(filepath: str) -> Union[Epub, Mobi, Azw3, FictionBook]:
file_ext = os.path.splitext(filepath)[1]
if file_ext == ".epub":
@@ -1390,10 +1500,10 @@ def truncate(teks: str, subtitution_text: str, maxlen: int, startsub: int = 0) -
Truncate text
eg.
- teks: 'This is long silly dummy text'
- subtitution_text: '...'
- maxlen: 12
- startsub: 3
+ :param teks: 'This is long silly dummy text'
+ :param subtitution_text: '...'
+ :param maxlen: 12
+ :param startsub: 3
:return: 'This...ly dummy text'
"""
if startsub > maxlen:
@@ -1433,7 +1543,7 @@ def dots_path(curr, tofi):
return "/".join(candir + tofi)
-def find_curr_toc_id(
+def find_current_content_index(
toc_entries: Tuple[TocEntry], toc_secid: Mapping[str, int], index: int, y: int
) -> int:
ntoc = 0
@@ -1449,13 +1559,7 @@ def count_letters(ebook: Union[Epub, Mobi, Azw3, FictionBook]) -> LettersCount:
cumulative_counts: List[int] = []
for i in ebook.contents:
content = ebook.get_raw_text(i)
- parser = HTMLtoLines()
- # try:
- parser.feed(content)
- parser.close()
- # except:
- # pass
- src_lines = parser.get_structured_text()
+ src_lines = parse_html(content)
cumulative_counts.append(sum(per_content_counts))
per_content_counts.append(sum([len(re.sub("\s", "", j)) for j in src_lines]))
@@ -1706,6 +1810,8 @@ class Reader:
# to build help menu text
self.keymap_user_dict = config.keymap_user_dict
+ self.seamless = self.setting.SeamlessBetweenChapters
+
# keys that will make
# windows exit and return the said key
self._win_keys = (
@@ -2013,9 +2119,8 @@ class Reader:
return NoUpdate()
def searching(
- self, board: InfiniBoard, src, reading_state: ReadingState, tot
+ self, board: InfiniBoard, src: Sequence[str], reading_state: ReadingState, tot
) -> Union[NoUpdate, ReadingState, Key]:
- # TODO: annotate this
rows, cols = self.screen.getmaxyx()
# unnecessary
@@ -2053,13 +2158,17 @@ class Reader:
and reading_state.content_index + 1 < tot
):
return ReadingState(
- content_index=reading_state.content_index + 1, textwidth=reading_state.textwidth
+ content_index=reading_state.content_index + 1,
+ textwidth=reading_state.textwidth,
+ row=0,
)
elif (
self.search_data.direction == Direction.BACKWARD and reading_state.content_index > 0
):
return ReadingState(
- content_index=reading_state.content_index - 1, textwidth=reading_state.textwidth
+ content_index=reading_state.content_index - 1,
+ textwidth=reading_state.textwidth,
+ row=0,
)
else:
s = 0
@@ -2077,6 +2186,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index + 1,
textwidth=reading_state.textwidth,
+ row=0,
)
elif s == Key("N") and reading_state.content_index + 1 == tot:
self.search_data = dataclasses.replace(
@@ -2085,6 +2195,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index - 1,
textwidth=reading_state.textwidth,
+ row=0,
)
self.screen.clear()
@@ -2102,7 +2213,9 @@ class Reader:
if self.search_data.direction == Direction.FORWARD:
if reading_state.row > found[-1][0]:
return ReadingState(
- content_index=reading_state.content_index + 1, textwidth=reading_state.textwidth
+ content_index=reading_state.content_index + 1,
+ textwidth=reading_state.textwidth,
+ row=0,
)
for n, i in enumerate(found):
if i[0] >= reading_state.row:
@@ -2136,6 +2249,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index + 1,
textwidth=reading_state.textwidth,
+ row=0,
)
else:
s = 0
@@ -2159,6 +2273,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index - 1,
textwidth=reading_state.textwidth,
+ row=0,
)
else:
s = 0
@@ -2271,6 +2386,8 @@ class Reader:
return k
def savestate(self, reading_state: ReadingState) -> None:
+ if self.seamless:
+ reading_state = Reader.adjust_seamless_reading_state(reading_state)
self.state.set_last_read(self.ebook)
self.state.set_last_reading_state(self.ebook, reading_state)
@@ -2321,19 +2438,73 @@ class Reader:
contents = self.ebook.contents
toc_entries = self.ebook.toc_entries
- content_path = contents[reading_state.content_index]
- content = self.ebook.get_raw_text(content_path)
+ if self.seamless:
+ text_structure: TextStructure = TextStructure(
+ text_lines=tuple(), image_maps=dict(), section_rows=dict(), formatting=tuple()
+ )
+ toc_entries_tmp: List[TocEntry] = []
+ section_rows_tmp: Mapping[str, int] = dict()
+ totlines_per_content: Sequence[int] = [] # only defined when Seamless==True
+ for n, content in enumerate(contents):
+ starting_line = sum(totlines_per_content)
+ text_structure_tmp = parse_html(
+ self.ebook.get_raw_text(content),
+ textwidth=reading_state.textwidth,
+ section_ids=set(toc_entry.section for toc_entry in toc_entries),
+ starting_line=starting_line,
+ )
+ totlines_per_content.append(len(text_structure_tmp.text_lines))
- parser = HTMLtoLines(set(toc_entry.section for toc_entry in toc_entries))
- # try:
- parser.feed(content)
- parser.close()
- # except:
- # pass
+ for toc_entry in toc_entries:
+ if toc_entry.content_index == n:
+ if toc_entry.section:
+ toc_entries_tmp.append(dataclasses.replace(toc_entry, content_index=0))
+ else:
+ section_id_tmp = str(uuid.uuid4())
+ toc_entries_tmp.append(
+ TocEntry(
+ label=toc_entry.label, content_index=0, section=section_id_tmp
+ )
+ )
+ section_rows_tmp[section_id_tmp] = starting_line
- # src_lines, imgs, toc_secid, formatting = parser.get_structured_text(reading_state.textwidth)
- text_structure = parser.get_structured_text(reading_state.textwidth)
- totlines = len(text_structure.text_lines) + 1 # 1 extra line for suffix
+ text_structure = merge_text_structures(text_structure, text_structure_tmp)
+
+ # adjustment
+ contents = [contents[0]]
+ toc_entries = toc_entries_tmp
+ text_structure = dataclasses.replace(
+ text_structure, section_rows={**text_structure.section_rows, **section_rows_tmp}
+ )
+ reading_state = dataclasses.replace(
+ reading_state,
+ content_index=0,
+ row=reading_state.row + sum(totlines_per_content[: reading_state.content_index]),
+ rel_pctg=(
+ reading_state.row + sum(totlines_per_content[: reading_state.content_index])
+ )
+ / len(text_structure.text_lines)
+ if reading_state.rel_pctg
+ else None,
+ )
+ # objects that only exist when Setting.Seamless==True
+ totlines_per_content = tuple(totlines_per_content)
+ Reader.adjust_seamless_reading_state = staticmethod(
+ lambda reading_state: construct_relative_reading_state(
+ reading_state, totlines_per_content
+ )
+ )
+
+ else:
+ content_path = contents[reading_state.content_index]
+ content = self.ebook.get_raw_text(content_path)
+ text_structure = parse_html(
+ content,
+ textwidth=reading_state.textwidth,
+ section_ids=set(toc_entry.section for toc_entry in toc_entries),
+ )
+
+ totlines = len(text_structure.text_lines)
if reading_state.row < 0 and totlines <= rows * self.spread:
reading_state = dataclasses.replace(reading_state, row=0)
@@ -2421,6 +2592,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index,
textwidth=reading_state.textwidth,
+ row=reading_state.row,
rel_pctg=reading_state.row / totlines,
)
@@ -2448,22 +2620,17 @@ class Reader:
elif k in self.keymap.PageUp:
if reading_state.row == 0 and reading_state.content_index != 0:
self.page_animation = Direction.BACKWARD
- tmp_parser = HTMLtoLines()
- tmp_parser.feed(
- self.ebook.get_raw_text(contents[reading_state.content_index - 1])
+ text_structure_content_before = parse_html(
+ self.ebook.get_raw_text(contents[reading_state.content_index - 1]),
+ textwidth=reading_state.textwidth,
)
- tmp_parser.close()
return ReadingState(
content_index=reading_state.content_index - 1,
textwidth=reading_state.textwidth,
row=rows
* self.spread
* (
- len(
- tmp_parser.get_structured_text(
- reading_state.textwidth
- ).text_lines
- )
+ len(text_structure_content_before.text_lines)
// (rows * self.spread)
),
)
@@ -2495,6 +2662,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index + 1,
textwidth=reading_state.textwidth,
+ row=0,
)
else:
reading_state = dataclasses.replace(reading_state, row=totlines - rows)
@@ -2510,6 +2678,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index + 1,
textwidth=reading_state.textwidth,
+ row=0,
)
# elif k in K["HalfScreenUp"] | K["HalfScreenDown"]:
@@ -2518,7 +2687,7 @@ class Reader:
# continue
elif k in self.keymap.NextChapter:
- ntoc = find_curr_toc_id(
+ ntoc = find_current_content_index(
toc_entries,
text_structure.section_rows,
reading_state.content_index,
@@ -2539,11 +2708,12 @@ class Reader:
return ReadingState(
content_index=toc_entries[ntoc + 1].content_index,
textwidth=reading_state.textwidth,
+ row=0,
section=toc_entries[ntoc + 1].section,
)
elif k in self.keymap.PrevChapter:
- ntoc = find_curr_toc_id(
+ ntoc = find_current_content_index(
toc_entries,
text_structure.section_rows,
reading_state.content_index,
@@ -2561,11 +2731,12 @@ class Reader:
return ReadingState(
content_index=toc_entries[ntoc - 1].content_index,
textwidth=reading_state.textwidth,
+ row=0,
section=toc_entries[ntoc - 1].section,
)
elif k in self.keymap.BeginningOfCh:
- ntoc = find_curr_toc_id(
+ ntoc = find_current_content_index(
toc_entries,
text_structure.section_rows,
reading_state.content_index,
@@ -2580,7 +2751,7 @@ class Reader:
reading_state = dataclasses.replace(reading_state, row=0)
elif k in self.keymap.EndOfCh:
- ntoc = find_curr_toc_id(
+ ntoc = find_current_content_index(
toc_entries,
text_structure.section_rows,
reading_state.content_index,
@@ -2614,7 +2785,7 @@ class Reader:
self.keymap.TableOfContents,
)
continue
- ntoc = find_curr_toc_id(
+ ntoc = find_current_content_index(
toc_entries,
text_structure.section_rows,
reading_state.content_index,
@@ -2637,6 +2808,7 @@ class Reader:
return ReadingState(
content_index=toc_entries[fllwd].content_index,
textwidth=reading_state.textwidth,
+ row=0,
section=toc_entries[fllwd].section,
)
@@ -2655,12 +2827,9 @@ class Reader:
and (reading_state.textwidth + count) < cols - 4
and self.spread == 1
):
- reading_state = dataclasses.replace(
- reading_state, textwidth=reading_state.textwidth + count
- )
- return ReadingState(
- content_index=reading_state.content_index,
- textwidth=reading_state.textwidth,
+ return dataclasses.replace(
+ reading_state,
+ textwidth=reading_state.textwidth + count,
rel_pctg=reading_state.row / totlines,
)
@@ -2669,12 +2838,9 @@ class Reader:
and reading_state.textwidth >= 22
and self.spread == 1
):
- reading_state = dataclasses.replace(
- reading_state, textwidth=reading_state.textwidth - count
- )
- return ReadingState(
- content_index=reading_state.content_index,
- textwidth=reading_state.textwidth,
+ return dataclasses.replace(
+ reading_state,
+ textwidth=reading_state.textwidth - count,
rel_pctg=reading_state.row / totlines,
)
@@ -2684,12 +2850,15 @@ class Reader:
if reading_state.textwidth != 80 and cols - 4 >= 80:
return ReadingState(
content_index=reading_state.content_index,
+ textwidth=80,
+ row=reading_state.row,
rel_pctg=reading_state.row / totlines,
)
else:
return ReadingState(
content_index=reading_state.content_index,
textwidth=cols - 4,
+ row=reading_state.row,
rel_pctg=reading_state.row / totlines,
)
else:
@@ -2698,15 +2867,16 @@ class Reader:
reading_state = dataclasses.replace(reading_state, textwidth=20)
elif reading_state.textwidth >= cols - 4:
reading_state = dataclasses.replace(reading_state, textwidth=cols - 4)
+
return ReadingState(
content_index=reading_state.content_index,
textwidth=reading_state.textwidth,
+ row=reading_state.row,
rel_pctg=reading_state.row / totlines,
)
elif k in self.keymap.RegexSearch:
ret_object = self.searching(
- # pad,
board,
text_structure.text_lines,
reading_state,
@@ -2770,6 +2940,18 @@ class Reader:
if image_path:
try:
if self.ebook.__class__.__name__ in {"Epub", "Mobi", "Azw3"}:
+ # self.seamless adjustment
+ if self.seamless:
+ content_path = self.ebook.contents[
+ Reader.adjust_seamless_reading_state(
+ reading_state
+ ).content_index
+ ]
+ # for n, content in enumerate(self.ebook.contents):
+ # content_path = content
+ # if reading_state.row < sum(totlines_per_content[:n]):
+ # break
+
image_path = dots_path(content_path, image_path)
imgnm, imgbstr = self.ebook.get_img_bytestr(image_path)
k = self.open_image(board, imgnm, imgbstr)
@@ -2911,6 +3093,7 @@ class Reader:
return ReadingState(
content_index=reading_state.content_index,
textwidth=cols - 4,
+ row=0,
rel_pctg=reading_state.row / totlines,
)
else:
@@ -3031,6 +3214,8 @@ def preread(stdscr, filepath: str):
while True:
reading_state = reader.read(reading_state)
reader.show_loader()
+ if reader.seamless:
+ reading_state = Reader.adjust_seamless_reading_state(reading_state)
finally:
reader.cleanup()
@@ -3153,13 +3338,7 @@ def parse_cli_args() -> str:
sys.exit("ERROR: Badly-structured ebook.\n" + str(e))
for i in ebook.contents:
content = ebook.get_raw_text(i)
- parser = HTMLtoLines()
- # try:
- parser.feed(content)
- parser.close()
- # except:
- # pass
- src_lines = parser.get_structured_text()
+ src_lines = parse_html(content)
# sys.stdout.reconfigure(encoding="utf-8") # Python>=3.7
for j in src_lines:
sys.stdout.buffer.write((j + "\n\n").encode("utf-8"))
diff --git a/setup.py b/setup.py
index a073e21..07bc177 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ if sys.platform == "win32":
setup(
name="epy-reader",
- version="2021.10.25",
+ version="2021.10.29",
description="Terminal/CLI Ebook (epub, fb2, mobi, azw3) Reader",
long_description=long_description,
long_description_content_type="text/markdown",