txt2ebook 0.1.156__py3-none-any.whl → 0.1.158__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- txt2ebook/formats/base.py +93 -0
- txt2ebook/formats/gmi.py +68 -81
- txt2ebook/formats/md.py +69 -81
- txt2ebook/formats/txt.py +75 -105
- txt2ebook/formats/typ.py +40 -3
- txt2ebook/subcommands/massage.py +30 -9
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/METADATA +17 -1
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/RECORD +12 -12
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/WHEEL +0 -0
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/entry_points.txt +0 -0
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/licenses/LICENSE.md +0 -0
- {txt2ebook-0.1.156.dist-info → txt2ebook-0.1.158.dist-info}/top_level.txt +0 -0
txt2ebook/formats/base.py
CHANGED
@@ -24,6 +24,7 @@ import shutil
|
|
24
24
|
import subprocess
|
25
25
|
import sys
|
26
26
|
from abc import ABC, abstractmethod
|
27
|
+
from datetime import datetime as dt
|
27
28
|
from importlib import import_module
|
28
29
|
from pathlib import Path
|
29
30
|
|
@@ -134,6 +135,98 @@ class BaseWriter(ABC):
|
|
134
135
|
file.parent, self.config.output_folder, lower_underscore(file.stem)
|
135
136
|
).with_suffix(extension)
|
136
137
|
|
138
|
+
def _get_toc_content_for_split(self) -> str:
|
139
|
+
raise NotImplementedError
|
140
|
+
|
141
|
+
def _get_volume_chapter_content_for_split(
|
142
|
+
self, volume: Volume, chapter: Chapter
|
143
|
+
) -> str:
|
144
|
+
raise NotImplementedError
|
145
|
+
|
146
|
+
def _get_chapter_content_for_split(self, chapter: Chapter) -> str:
|
147
|
+
raise NotImplementedError
|
148
|
+
|
149
|
+
def _get_file_extension_for_split(self) -> str:
|
150
|
+
raise NotImplementedError
|
151
|
+
|
152
|
+
def _export_multiple_files(self) -> None:
|
153
|
+
logger.info("Split multiple files")
|
154
|
+
|
155
|
+
extension = self._get_file_extension_for_split()
|
156
|
+
txt_filename = Path(self.config.input_file.name)
|
157
|
+
|
158
|
+
export_filename = self._get_metadata_filename_for_split(txt_filename, extension)
|
159
|
+
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
160
|
+
logger.info("Creating %s", export_filename)
|
161
|
+
with open(export_filename, "w", encoding="utf8") as file:
|
162
|
+
file.write(self._to_metadata_txt())
|
163
|
+
|
164
|
+
sc_seq = 1
|
165
|
+
if self.config.with_toc:
|
166
|
+
export_filename = self._get_toc_filename_for_split(txt_filename, extension)
|
167
|
+
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
168
|
+
logger.info("Creating %s", export_filename)
|
169
|
+
with open(export_filename, "w", encoding="utf8") as file:
|
170
|
+
file.write(self._get_toc_content_for_split())
|
171
|
+
|
172
|
+
sc_seq = 2
|
173
|
+
|
174
|
+
for section in self.book.toc:
|
175
|
+
section_seq = str(sc_seq).rjust(2, "0")
|
176
|
+
|
177
|
+
ct_seq = 0
|
178
|
+
if isinstance(section, Volume):
|
179
|
+
for chapter in section.chapters:
|
180
|
+
chapter_seq = str(ct_seq).rjust(2, "0")
|
181
|
+
export_filename = self._get_volume_chapter_filename_for_split(
|
182
|
+
txt_filename, section_seq, chapter_seq, section, chapter, extension
|
183
|
+
)
|
184
|
+
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
185
|
+
logger.info("Creating %s", export_filename)
|
186
|
+
with open(export_filename, "w", encoding="utf8") as file:
|
187
|
+
file.write(
|
188
|
+
self._get_volume_chapter_content_for_split(
|
189
|
+
section, chapter
|
190
|
+
)
|
191
|
+
)
|
192
|
+
ct_seq = ct_seq + 1
|
193
|
+
if isinstance(section, Chapter):
|
194
|
+
export_filename = self._get_chapter_filename_for_split(
|
195
|
+
txt_filename, section_seq, section, extension
|
196
|
+
)
|
197
|
+
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
198
|
+
logger.info("Creating %s", export_filename)
|
199
|
+
with open(export_filename, "w", encoding="utf8") as file:
|
200
|
+
file.write(self._get_chapter_content_for_split(section))
|
201
|
+
|
202
|
+
sc_seq = sc_seq + 1
|
203
|
+
|
204
|
+
@abstractmethod
|
205
|
+
def _get_metadata_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
206
|
+
raise NotImplementedError
|
207
|
+
|
208
|
+
@abstractmethod
|
209
|
+
def _get_toc_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
210
|
+
raise NotImplementedError
|
211
|
+
|
212
|
+
@abstractmethod
|
213
|
+
def _get_volume_chapter_filename_for_split(
|
214
|
+
self,
|
215
|
+
txt_filename: Path,
|
216
|
+
section_seq: str,
|
217
|
+
chapter_seq: str,
|
218
|
+
volume: Volume,
|
219
|
+
chapter: Chapter,
|
220
|
+
extension: str,
|
221
|
+
) -> Path:
|
222
|
+
raise NotImplementedError
|
223
|
+
|
224
|
+
@abstractmethod
|
225
|
+
def _get_chapter_filename_for_split(
|
226
|
+
self, txt_filename: Path, section_seq: str, chapter: Chapter, extension: str
|
227
|
+
) -> Path:
|
228
|
+
raise NotImplementedError
|
229
|
+
|
137
230
|
def _to_metadata_txt(self) -> str:
|
138
231
|
metadata = [
|
139
232
|
self._("title:") + self.book.title,
|
txt2ebook/formats/gmi.py
CHANGED
@@ -34,99 +34,86 @@ class GmiWriter(BaseWriter):
|
|
34
34
|
if self.config.split_volume_and_chapter:
|
35
35
|
self._export_multiple_files()
|
36
36
|
else:
|
37
|
-
self.
|
37
|
+
output_filename = self._output_filename(".gmi")
|
38
|
+
output_filename.parent.mkdir(parents=True, exist_ok=True)
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
with open(output_filename, "w", encoding="utf8") as file:
|
41
|
+
logger.info("Generate Gemini file: %s", output_filename.resolve())
|
42
|
+
file.write(self._to_gmi())
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
+
if self.config.open:
|
45
|
+
self._open_file(output_filename)
|
46
|
+
|
47
|
+
def _get_toc_content_for_split(self) -> str:
|
48
|
+
return self._to_toc("*", "# ")
|
49
|
+
|
50
|
+
def _get_volume_chapter_content_for_split(
|
51
|
+
self, volume: Volume, chapter: Chapter
|
52
|
+
) -> str:
|
53
|
+
return self._to_volume_chapter_txt(volume, chapter)
|
54
|
+
|
55
|
+
def _get_chapter_content_for_split(self, chapter: Chapter) -> str:
|
56
|
+
return self._to_chapter_txt(chapter)
|
57
|
+
|
58
|
+
def _get_file_extension_for_split(self) -> str:
|
59
|
+
return ".gmi"
|
60
|
+
|
61
|
+
def _get_metadata_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
62
|
+
return Path(
|
44
63
|
txt_filename.resolve().parent.joinpath(
|
45
64
|
self.config.output_folder,
|
46
65
|
lower_underscore(
|
47
|
-
f"00_{txt_filename.stem}_" + self._("metadata") +
|
66
|
+
f"00_{txt_filename.stem}_" + self._("metadata") + extension
|
48
67
|
),
|
49
68
|
)
|
50
69
|
)
|
51
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
52
|
-
logger.info("Creating %s", export_filename)
|
53
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
54
|
-
file.write(self._to_metadata_txt())
|
55
|
-
|
56
|
-
sc_seq = 1
|
57
|
-
if self.config.with_toc:
|
58
|
-
export_filename = Path(
|
59
|
-
txt_filename.resolve().parent.joinpath(
|
60
|
-
self.config.output_folder,
|
61
|
-
lower_underscore(
|
62
|
-
f"01_{txt_filename.stem}_" + self._("toc") + ".gmi"
|
63
|
-
),
|
64
|
-
)
|
65
|
-
)
|
66
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
67
|
-
logger.info("Creating %s", export_filename)
|
68
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
69
|
-
file.write(self._to_toc("*", "# "))
|
70
|
-
|
71
|
-
sc_seq = 2
|
72
|
-
|
73
|
-
for section in self.book.toc:
|
74
|
-
section_seq = str(sc_seq).rjust(2, "0")
|
75
70
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
f"_{section.title}"
|
86
|
-
f"_{chapter.title}"
|
87
|
-
".gmi"
|
88
|
-
)
|
89
|
-
)
|
90
|
-
|
91
|
-
export_filename = Path(
|
92
|
-
txt_filename.resolve().parent.joinpath(
|
93
|
-
self.config.output_folder, filename
|
94
|
-
)
|
95
|
-
)
|
96
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
97
|
-
logger.info("Creating %s", export_filename)
|
98
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
99
|
-
file.write(
|
100
|
-
self._to_volume_chapter_txt(section, chapter)
|
101
|
-
)
|
102
|
-
ct_seq = ct_seq + 1
|
103
|
-
if isinstance(section, Chapter):
|
104
|
-
filename = lower_underscore(
|
105
|
-
(f"{section_seq}_{txt_filename.stem}_{section.title}.gmi")
|
106
|
-
)
|
71
|
+
def _get_toc_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
72
|
+
return Path(
|
73
|
+
txt_filename.resolve().parent.joinpath(
|
74
|
+
self.config.output_folder,
|
75
|
+
lower_underscore(
|
76
|
+
f"01_{txt_filename.stem}_" + self._("toc") + extension
|
77
|
+
),
|
78
|
+
)
|
79
|
+
)
|
107
80
|
|
108
|
-
|
109
|
-
|
110
|
-
|
81
|
+
def _get_volume_chapter_filename_for_split(
|
82
|
+
self,
|
83
|
+
txt_filename: Path,
|
84
|
+
section_seq: str,
|
85
|
+
chapter_seq: str,
|
86
|
+
volume: Volume,
|
87
|
+
chapter: Chapter,
|
88
|
+
extension: str,
|
89
|
+
) -> Path:
|
90
|
+
return Path(
|
91
|
+
txt_filename.resolve().parent.joinpath(
|
92
|
+
self.config.output_folder,
|
93
|
+
lower_underscore(
|
94
|
+
(
|
95
|
+
f"{section_seq}"
|
96
|
+
f"_{chapter_seq}"
|
97
|
+
f"_{txt_filename.stem}"
|
98
|
+
f"_{volume.title}"
|
99
|
+
f"_{chapter.title}"
|
100
|
+
f"{extension}"
|
111
101
|
)
|
112
|
-
)
|
113
|
-
|
114
|
-
|
115
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
116
|
-
file.write(self._to_chapter_txt(section))
|
117
|
-
|
118
|
-
sc_seq = sc_seq + 1
|
119
|
-
|
120
|
-
def _new_file(self) -> None:
|
121
|
-
new_filename = self._output_filename(".gmi")
|
122
|
-
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
123
|
-
|
124
|
-
with open(new_filename, "w", encoding="utf8") as file:
|
125
|
-
logger.info("Generate GemText file: %s", new_filename.resolve())
|
126
|
-
file.write(self._to_gmi())
|
102
|
+
),
|
103
|
+
)
|
104
|
+
)
|
127
105
|
|
128
|
-
|
129
|
-
|
106
|
+
def _get_chapter_filename_for_split(
|
107
|
+
self, txt_filename: Path, section_seq: str, chapter: Chapter, extension: str
|
108
|
+
) -> Path:
|
109
|
+
return Path(
|
110
|
+
txt_filename.resolve().parent.joinpath(
|
111
|
+
self.config.output_folder,
|
112
|
+
lower_underscore(
|
113
|
+
(f"{section_seq}_{txt_filename.stem}_{chapter.title}{extension}")
|
114
|
+
),
|
115
|
+
)
|
116
|
+
)
|
130
117
|
|
131
118
|
def _to_gmi(self) -> str:
|
132
119
|
toc = self._to_toc("*", "# ") if self.config.with_toc else ""
|
txt2ebook/formats/md.py
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
import logging
|
19
19
|
from pathlib import Path
|
20
|
+
from pathlib import Path
|
20
21
|
|
21
22
|
from txt2ebook.formats.base import BaseWriter
|
22
23
|
from txt2ebook.helpers import lower_underscore
|
@@ -33,99 +34,86 @@ class MdWriter(BaseWriter):
|
|
33
34
|
if self.config.split_volume_and_chapter:
|
34
35
|
self._export_multiple_files()
|
35
36
|
else:
|
36
|
-
self.
|
37
|
+
output_filename = self._output_filename(".md")
|
38
|
+
output_filename.parent.mkdir(parents=True, exist_ok=True)
|
39
|
+
|
40
|
+
with open(output_filename, "w", encoding="utf8") as file:
|
41
|
+
logger.info("Generate Markdown file: %s", output_filename.resolve())
|
42
|
+
file.write(self._to_md())
|
43
|
+
|
44
|
+
if self.config.open:
|
45
|
+
self._open_file(output_filename)
|
46
|
+
|
47
|
+
def _get_toc_content_for_split(self) -> str:
|
48
|
+
return self._to_toc("-", "# ")
|
49
|
+
|
50
|
+
def _get_volume_chapter_content_for_split(
|
51
|
+
self, volume: Volume, chapter: Chapter
|
52
|
+
) -> str:
|
53
|
+
return self._to_volume_chapter_txt(volume, chapter)
|
37
54
|
|
38
|
-
def
|
39
|
-
|
55
|
+
def _get_chapter_content_for_split(self, chapter: Chapter) -> str:
|
56
|
+
return self._to_chapter_txt(chapter)
|
40
57
|
|
41
|
-
|
42
|
-
|
58
|
+
def _get_file_extension_for_split(self) -> str:
|
59
|
+
return ".md"
|
60
|
+
|
61
|
+
def _get_metadata_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
62
|
+
return Path(
|
43
63
|
txt_filename.resolve().parent.joinpath(
|
44
64
|
self.config.output_folder,
|
45
65
|
lower_underscore(
|
46
|
-
f"00_{txt_filename.stem}_" + self._("metadata") +
|
66
|
+
f"00_{txt_filename.stem}_" + self._("metadata") + extension
|
47
67
|
),
|
48
68
|
)
|
49
69
|
)
|
50
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
51
|
-
logger.info("Creating %s", export_filename)
|
52
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
53
|
-
file.write(self._to_metadata_txt())
|
54
|
-
|
55
|
-
sc_seq = 1
|
56
|
-
if self.config.with_toc:
|
57
|
-
export_filename = Path(
|
58
|
-
txt_filename.resolve().parent.joinpath(
|
59
|
-
self.config.output_folder,
|
60
|
-
lower_underscore(
|
61
|
-
f"01_{txt_filename.stem}_" + self._("toc") + ".md"
|
62
|
-
),
|
63
|
-
)
|
64
|
-
)
|
65
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
66
|
-
logger.info("Creating %s", export_filename)
|
67
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
68
|
-
file.write(self._to_toc("-", "# "))
|
69
|
-
|
70
|
-
sc_seq = 2
|
71
|
-
|
72
|
-
for section in self.book.toc:
|
73
|
-
section_seq = str(sc_seq).rjust(2, "0")
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
f"_{section.title}"
|
85
|
-
f"_{chapter.title}"
|
86
|
-
".md"
|
87
|
-
)
|
88
|
-
)
|
89
|
-
|
90
|
-
export_filename = Path(
|
91
|
-
txt_filename.resolve().parent.joinpath(
|
92
|
-
self.config.output_folder, filename
|
93
|
-
)
|
94
|
-
)
|
95
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
96
|
-
logger.info("Creating %s", export_filename)
|
97
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
98
|
-
file.write(
|
99
|
-
self._to_volume_chapter_txt(section, chapter)
|
100
|
-
)
|
101
|
-
ct_seq = ct_seq + 1
|
102
|
-
if isinstance(section, Chapter):
|
103
|
-
filename = lower_underscore(
|
104
|
-
(f"{section_seq}_{txt_filename.stem}_{section.title}.md")
|
105
|
-
)
|
71
|
+
def _get_toc_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
72
|
+
return Path(
|
73
|
+
txt_filename.resolve().parent.joinpath(
|
74
|
+
self.config.output_folder,
|
75
|
+
lower_underscore(
|
76
|
+
f"01_{txt_filename.stem}_" + self._("toc") + extension
|
77
|
+
),
|
78
|
+
)
|
79
|
+
)
|
106
80
|
|
107
|
-
|
108
|
-
|
109
|
-
|
81
|
+
def _get_volume_chapter_filename_for_split(
|
82
|
+
self,
|
83
|
+
txt_filename: Path,
|
84
|
+
section_seq: str,
|
85
|
+
chapter_seq: str,
|
86
|
+
volume: Volume,
|
87
|
+
chapter: Chapter,
|
88
|
+
extension: str,
|
89
|
+
) -> Path:
|
90
|
+
return Path(
|
91
|
+
txt_filename.resolve().parent.joinpath(
|
92
|
+
self.config.output_folder,
|
93
|
+
lower_underscore(
|
94
|
+
(
|
95
|
+
f"{section_seq}"
|
96
|
+
f"_{chapter_seq}"
|
97
|
+
f"_{txt_filename.stem}"
|
98
|
+
f"_{volume.title}"
|
99
|
+
f"_{chapter.title}"
|
100
|
+
f"{extension}"
|
110
101
|
)
|
111
|
-
)
|
112
|
-
|
113
|
-
|
114
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
115
|
-
file.write(self._to_chapter_txt(section))
|
116
|
-
|
117
|
-
sc_seq = sc_seq + 1
|
118
|
-
|
119
|
-
def _new_file(self) -> None:
|
120
|
-
new_filename = self._output_filename(".md")
|
121
|
-
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
122
|
-
|
123
|
-
with open(new_filename, "w", encoding="utf8") as file:
|
124
|
-
logger.info("Generate Markdown file: %s", new_filename.resolve())
|
125
|
-
file.write(self._to_md())
|
102
|
+
),
|
103
|
+
)
|
104
|
+
)
|
126
105
|
|
127
|
-
|
128
|
-
|
106
|
+
def _get_chapter_filename_for_split(
|
107
|
+
self, txt_filename: Path, section_seq: str, chapter: Chapter, extension: str
|
108
|
+
) -> Path:
|
109
|
+
return Path(
|
110
|
+
txt_filename.resolve().parent.joinpath(
|
111
|
+
self.config.output_folder,
|
112
|
+
lower_underscore(
|
113
|
+
(f"{section_seq}_{txt_filename.stem}_{chapter.title}{extension}")
|
114
|
+
),
|
115
|
+
)
|
116
|
+
)
|
129
117
|
|
130
118
|
def _to_md(self) -> str:
|
131
119
|
toc = self._to_toc("-", "# ") if self.config.with_toc else ""
|
txt2ebook/formats/txt.py
CHANGED
@@ -16,6 +16,7 @@
|
|
16
16
|
"""Convert and backup source text file into text as well."""
|
17
17
|
|
18
18
|
import logging
|
19
|
+
import shutil
|
19
20
|
from datetime import datetime as dt
|
20
21
|
from pathlib import Path
|
21
22
|
|
@@ -40,124 +41,93 @@ class TxtWriter(BaseWriter):
|
|
40
41
|
elif self.config.split_volume_and_chapter:
|
41
42
|
self._export_multiple_files()
|
42
43
|
else:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
output_filename = self._output_filename(".txt")
|
45
|
+
output_filename.parent.mkdir(parents=True, exist_ok=True)
|
46
|
+
|
47
|
+
if self.config.overwrite and output_filename == Path(
|
48
|
+
self.config.input_file.name
|
49
|
+
):
|
50
|
+
ymd_hms = dt.now().strftime("%Y%m%d_%H%M%S")
|
51
|
+
backup_filename = Path(
|
52
|
+
Path(self.config.input_file.name)
|
53
|
+
.resolve()
|
54
|
+
.parent.joinpath(
|
55
|
+
lower_underscore(
|
56
|
+
Path(self.config.input_file.name).stem
|
57
|
+
+ "_" + ymd_hms + ".txt"
|
58
|
+
)
|
59
|
+
)
|
60
|
+
)
|
61
|
+
logger.info("Backup source text file: %s", backup_filename.resolve())
|
62
|
+
shutil.copyfile(output_filename, backup_filename)
|
63
|
+
|
64
|
+
with open(output_filename, "w", encoding="utf8") as file:
|
65
|
+
logger.info("Generate TXT file: %s", output_filename.resolve())
|
66
|
+
file.write(self._to_txt())
|
67
|
+
|
68
|
+
if self.config.open:
|
69
|
+
self._open_file(output_filename)
|
70
|
+
|
71
|
+
|
47
72
|
|
48
|
-
|
49
|
-
logger.info("Split multiple files")
|
73
|
+
|
50
74
|
|
51
|
-
|
52
|
-
|
75
|
+
def _get_metadata_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
76
|
+
return Path(
|
53
77
|
txt_filename.resolve().parent.joinpath(
|
54
78
|
self.config.output_folder,
|
55
79
|
lower_underscore(
|
56
|
-
f"00_{txt_filename.stem}_" + self._("metadata") +
|
80
|
+
f"00_{txt_filename.stem}_" + self._("metadata") + extension
|
57
81
|
),
|
58
82
|
)
|
59
83
|
)
|
60
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
61
|
-
logger.info("Creating %s", export_filename)
|
62
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
63
|
-
file.write(self._to_metadata_txt())
|
64
|
-
|
65
|
-
sc_seq = 1
|
66
|
-
if self.config.with_toc:
|
67
|
-
export_filename = Path(
|
68
|
-
txt_filename.resolve().parent.joinpath(
|
69
|
-
self.config.output_folder,
|
70
|
-
lower_underscore(
|
71
|
-
f"01_{txt_filename.stem}_" + self._("toc") + ".txt"
|
72
|
-
),
|
73
|
-
)
|
74
|
-
)
|
75
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
76
|
-
logger.info("Creating %s", export_filename)
|
77
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
78
|
-
file.write(self._to_toc("-"))
|
79
|
-
|
80
|
-
sc_seq = 2
|
81
84
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
f"{section_seq}"
|
92
|
-
f"_{chapter_seq}"
|
93
|
-
f"_{txt_filename.stem}"
|
94
|
-
f"_{section.title}"
|
95
|
-
f"_{chapter.title}"
|
96
|
-
".txt"
|
97
|
-
)
|
98
|
-
)
|
99
|
-
|
100
|
-
export_filename = Path(
|
101
|
-
txt_filename.resolve().parent.joinpath(
|
102
|
-
self.config.output_folder, filename
|
103
|
-
)
|
104
|
-
)
|
105
|
-
export_filename.parent.mkdir(parents=True, exist_ok=True)
|
106
|
-
logger.info("Creating %s", export_filename)
|
107
|
-
with open(export_filename, "w", encoding="utf8") as file:
|
108
|
-
file.write(
|
109
|
-
self._to_volume_chapter_txt(section, chapter)
|
110
|
-
)
|
111
|
-
ct_seq = ct_seq + 1
|
112
|
-
if isinstance(section, Chapter):
|
113
|
-
filename = lower_underscore(
|
114
|
-
(f"{section_seq}_{txt_filename.stem}_{section.title}.txt")
|
115
|
-
)
|
85
|
+
def _get_toc_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
86
|
+
return Path(
|
87
|
+
txt_filename.resolve().parent.joinpath(
|
88
|
+
self.config.output_folder,
|
89
|
+
lower_underscore(
|
90
|
+
f"01_{txt_filename.stem}_" + self._("toc") + extension
|
91
|
+
),
|
92
|
+
)
|
93
|
+
)
|
116
94
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
lower_underscore(
|
138
|
-
txt_filename.stem + "_" + ymd_hms + ".txt"
|
95
|
+
def _get_volume_chapter_filename_for_split(
|
96
|
+
self,
|
97
|
+
txt_filename: Path,
|
98
|
+
section_seq: str,
|
99
|
+
chapter_seq: str,
|
100
|
+
volume: Volume,
|
101
|
+
chapter: Chapter,
|
102
|
+
extension: str,
|
103
|
+
) -> Path:
|
104
|
+
return Path(
|
105
|
+
txt_filename.resolve().parent.joinpath(
|
106
|
+
self.config.output_folder,
|
107
|
+
lower_underscore(
|
108
|
+
(
|
109
|
+
f"{section_seq}"
|
110
|
+
f"_{chapter_seq}"
|
111
|
+
f"_{txt_filename.stem}"
|
112
|
+
f"_{volume.title}"
|
113
|
+
f"_{chapter.title}"
|
114
|
+
f"{extension}"
|
139
115
|
)
|
140
|
-
)
|
116
|
+
),
|
141
117
|
)
|
118
|
+
)
|
142
119
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
with open(txt_filename, "w", encoding="utf8") as file:
|
156
|
-
file.write(self._to_txt())
|
157
|
-
logger.info("Overwrite txt file: %s", txt_filename.resolve())
|
158
|
-
|
159
|
-
if self.config.open:
|
160
|
-
self._open_file(txt_filename)
|
120
|
+
def _get_chapter_filename_for_split(
|
121
|
+
self, txt_filename: Path, section_seq: str, chapter: Chapter, extension: str
|
122
|
+
) -> Path:
|
123
|
+
return Path(
|
124
|
+
txt_filename.resolve().parent.joinpath(
|
125
|
+
self.config.output_folder,
|
126
|
+
lower_underscore(
|
127
|
+
(f"{section_seq}_{txt_filename.stem}_{chapter.title}{extension}")
|
128
|
+
),
|
129
|
+
)
|
130
|
+
)
|
161
131
|
|
162
132
|
def _to_txt(self) -> str:
|
163
133
|
toc = self._to_toc("-") if self.config.with_toc else ""
|
txt2ebook/formats/typ.py
CHANGED
@@ -18,11 +18,13 @@
|
|
18
18
|
import importlib.resources as importlib_res
|
19
19
|
import logging
|
20
20
|
import textwrap
|
21
|
+
from pathlib import Path
|
21
22
|
|
22
23
|
import importlib_resources
|
23
24
|
import typst
|
24
25
|
|
25
26
|
from txt2ebook.formats.base import BaseWriter
|
27
|
+
from txt2ebook.helpers import lower_underscore
|
26
28
|
from txt2ebook.models import Chapter, Volume
|
27
29
|
|
28
30
|
# workaround for Python 3.8
|
@@ -43,9 +45,6 @@ class TypWriter(BaseWriter):
|
|
43
45
|
|
44
46
|
def write(self) -> None:
|
45
47
|
"""Generate Typst files."""
|
46
|
-
self._new_file()
|
47
|
-
|
48
|
-
def _new_file(self) -> None:
|
49
48
|
new_filename = self._output_filename(".typ")
|
50
49
|
new_filename.parent.mkdir(parents=True, exist_ok=True)
|
51
50
|
|
@@ -210,6 +209,20 @@ class TypWriter(BaseWriter):
|
|
210
209
|
|
211
210
|
return self.config.paragraph_separator.join(pars)
|
212
211
|
|
212
|
+
def _get_file_extension_for_split(self) -> str:
|
213
|
+
return ".typ"
|
214
|
+
|
215
|
+
def _get_toc_content_for_split(self) -> str:
|
216
|
+
return self._to_outline()
|
217
|
+
|
218
|
+
def _get_volume_chapter_content_for_split(
|
219
|
+
self, volume: Volume, chapter: Chapter
|
220
|
+
) -> str:
|
221
|
+
return self._to_volume_chapter_txt(volume, chapter)
|
222
|
+
|
223
|
+
def _get_chapter_content_for_split(self, chapter: Chapter) -> str:
|
224
|
+
return self._to_chapter_txt(chapter)
|
225
|
+
|
213
226
|
def _index_pages(self) -> str:
|
214
227
|
return textwrap.dedent(
|
215
228
|
"""
|
@@ -221,3 +234,27 @@ class TypWriter(BaseWriter):
|
|
221
234
|
]
|
222
235
|
"""
|
223
236
|
)
|
237
|
+
|
238
|
+
def _get_metadata_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
239
|
+
return Path(self._output_folder(), "metadata").with_suffix(extension)
|
240
|
+
|
241
|
+
def _get_toc_filename_for_split(self, txt_filename: Path, extension: str) -> Path:
|
242
|
+
return Path(self._output_folder(), "toc").with_suffix(extension)
|
243
|
+
|
244
|
+
def _get_volume_chapter_filename_for_split(
|
245
|
+
self,
|
246
|
+
txt_filename: Path,
|
247
|
+
section_seq: str,
|
248
|
+
chapter_seq: str,
|
249
|
+
volume: Volume,
|
250
|
+
chapter: Chapter,
|
251
|
+
extension: str,
|
252
|
+
) -> Path:
|
253
|
+
filename = f"{section_seq}-{lower_underscore(volume.title)}-{chapter_seq}-{lower_underscore(chapter.title)}"
|
254
|
+
return Path(self._output_folder(), filename).with_suffix(extension)
|
255
|
+
|
256
|
+
def _get_chapter_filename_for_split(
|
257
|
+
self, txt_filename: Path, section_seq: str, chapter: Chapter, extension: str
|
258
|
+
) -> Path:
|
259
|
+
filename = f"{section_seq}-{lower_underscore(chapter.title)}"
|
260
|
+
return Path(self._output_folder(), filename).with_suffix(extension)
|
txt2ebook/subcommands/massage.py
CHANGED
@@ -210,7 +210,7 @@ def run(args: argparse.Namespace) -> None:
|
|
210
210
|
"""Run massage subcommand.
|
211
211
|
|
212
212
|
Args:
|
213
|
-
args (argparse.Namespace):
|
213
|
+
args (argparse.Namespace): arguments from command line arguments
|
214
214
|
|
215
215
|
Returns:
|
216
216
|
None
|
@@ -472,7 +472,6 @@ def extract_metadata_and_body(_args, content: str) -> tuple:
|
|
472
472
|
metadata = match.group(0).strip()
|
473
473
|
body = content.replace(metadata, "", 1)
|
474
474
|
|
475
|
-
|
476
475
|
metadata_block = metadata.split("---")[1]
|
477
476
|
|
478
477
|
metadata_dict = {}
|
@@ -492,33 +491,38 @@ def extract_metadata_and_body(_args, content: str) -> tuple:
|
|
492
491
|
return (meta_str, body)
|
493
492
|
|
494
493
|
|
495
|
-
def do_single_newline(args, content: str) -> str:
|
494
|
+
def do_single_newline(args: argparse.Namespace, content: str) -> str:
|
496
495
|
"""Set single newline.
|
497
496
|
|
498
497
|
Args:
|
499
|
-
|
498
|
+
args (argparse.Namespace): arguments from command line arguments
|
499
|
+
content (str): The formatted book content
|
500
500
|
|
501
501
|
Returns:
|
502
502
|
str: The formatted book content.
|
503
503
|
"""
|
504
|
-
|
504
|
+
unwrap_content = _unwrap_content(args, content)
|
505
|
+
modified_content = re.sub(r"\n+", "\n\n", unwrap_content)
|
505
506
|
return modified_content
|
506
507
|
|
507
508
|
|
508
|
-
def do_wrapping(args, content: str) -> str:
|
509
|
+
def do_wrapping(args: argparse.Namespace, content: str) -> str:
|
509
510
|
"""Wrap or fill CJK text.
|
510
511
|
|
511
512
|
Args:
|
512
|
-
|
513
|
+
args (argparse.Namespace): arguments from command line arguments
|
514
|
+
content (str): The formatted book content
|
513
515
|
|
514
516
|
Returns:
|
515
517
|
str: The formatted book content.
|
516
518
|
"""
|
517
519
|
logger.info("Wrapping paragraph to width: %s", args.width)
|
518
520
|
|
521
|
+
unwrap_content = _unwrap_content(args, content)
|
522
|
+
|
523
|
+
# don't remove empty line and keep all formatting as it
|
519
524
|
paragraphs = []
|
520
|
-
|
521
|
-
for paragraph in content.split("\n"):
|
525
|
+
for paragraph in unwrap_content.split("\n"):
|
522
526
|
paragraph = paragraph.strip()
|
523
527
|
|
524
528
|
lines = cjkwrap.wrap(paragraph, width=args.width)
|
@@ -527,3 +531,20 @@ def do_wrapping(args, content: str) -> str:
|
|
527
531
|
|
528
532
|
wrapped_content = "\n".join(paragraphs)
|
529
533
|
return wrapped_content
|
534
|
+
|
535
|
+
|
536
|
+
def _unwrap_content(args: argparse.Namespace, content: str) -> str:
|
537
|
+
"""
|
538
|
+
Args:
|
539
|
+
args (argparse.Namespace): arguments from command line arguments
|
540
|
+
content (str): The formatted book content
|
541
|
+
|
542
|
+
Returns:
|
543
|
+
str: The formatted book content.
|
544
|
+
"""
|
545
|
+
paragraphs = content.split(args.paragraph_separator)
|
546
|
+
processed_paragraphs = []
|
547
|
+
for paragraph in paragraphs:
|
548
|
+
single_line_paragraph = " ".join(paragraph.splitlines())
|
549
|
+
processed_paragraphs.append(single_line_paragraph.strip())
|
550
|
+
return args.paragraph_separator.join(processed_paragraphs)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: txt2ebook
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.158
|
4
4
|
Summary: CLI tool to convert txt file to ebook format
|
5
5
|
Author-email: Kian-Meng Ang <kianmeng@cpan.org>
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
@@ -39,6 +39,22 @@ Requires-Dist: regex<2022,>=2021.11.10
|
|
39
39
|
Requires-Dist: reportlab<5,>=4.0.0
|
40
40
|
Requires-Dist: typing-extensions<5,>=4.5.0
|
41
41
|
Requires-Dist: typst>=0.13.0
|
42
|
+
Provides-Extra: test
|
43
|
+
Requires-Dist: pytest; extra == "test"
|
44
|
+
Requires-Dist: pytest-cov; extra == "test"
|
45
|
+
Requires-Dist: pytest-randomly; extra == "test"
|
46
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
47
|
+
Requires-Dist: scripttest; extra == "test"
|
48
|
+
Provides-Extra: doc
|
49
|
+
Requires-Dist: myst-parser; extra == "doc"
|
50
|
+
Requires-Dist: sphinx; extra == "doc"
|
51
|
+
Requires-Dist: sphinx-autobuild; extra == "doc"
|
52
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "doc"
|
53
|
+
Requires-Dist: sphinx-copybutton; extra == "doc"
|
54
|
+
Provides-Extra: lint
|
55
|
+
Requires-Dist: pre-commit; extra == "lint"
|
56
|
+
Requires-Dist: ruff; extra == "lint"
|
57
|
+
Requires-Dist: mypy; extra == "lint"
|
42
58
|
Dynamic: license-file
|
43
59
|
|
44
60
|
# txt2ebook
|
@@ -6,14 +6,14 @@ txt2ebook/parser.py,sha256=ITn6pGHO4vTfdrYouVV2mEe9jUM2zm3-FKEcspp2qzI,8968
|
|
6
6
|
txt2ebook/tokenizer.py,sha256=UGyOBGxlKOXJtvP2UFp38EgFym8-PAU3A7Jl9RF3w6Y,10299
|
7
7
|
txt2ebook/zh_utils.py,sha256=0Yq9r-JL4HntW68vFR6TBP9yQim1a07mfsh_sp-XmaE,4887
|
8
8
|
txt2ebook/formats/__init__.py,sha256=_fW9UuoOTFxCKlej6t-PsFzJOqDFLzVatCci9tcPQeE,1645
|
9
|
-
txt2ebook/formats/base.py,sha256=
|
9
|
+
txt2ebook/formats/base.py,sha256=3JIdLr0HowBYQL5-IdJKQa3eZD1a_cRYd2czfFRlg-0,9431
|
10
10
|
txt2ebook/formats/epub.py,sha256=IVz-FmYQlcChOw38YqfKy46bPVSIrHyxA_94iz06N3Y,6941
|
11
|
-
txt2ebook/formats/gmi.py,sha256=
|
12
|
-
txt2ebook/formats/md.py,sha256=
|
11
|
+
txt2ebook/formats/gmi.py,sha256=aIAoAG5HRNfC6OlkjMD54_wCveT0DXRaZCbTu1x8LYk,5692
|
12
|
+
txt2ebook/formats/md.py,sha256=lEsYyVWOV13aMt6WfspL2WQfSoC82urWYQx8kxa_6kY,5467
|
13
13
|
txt2ebook/formats/pdf.py,sha256=tr_ozVlL976yo7Ggny71zjOwzSd6tSnHTl7mcsLII_g,7263
|
14
14
|
txt2ebook/formats/tex.py,sha256=V5B1nPR-WzGc4jqWu-BqxfQhtQsUTKM_sZZJsCcDBAk,5897
|
15
|
-
txt2ebook/formats/txt.py,sha256=
|
16
|
-
txt2ebook/formats/typ.py,sha256=
|
15
|
+
txt2ebook/formats/txt.py,sha256=7LYxS6wlJre_GFKemaVsTOTez_dpJcpoo6Emezt6rjc,5905
|
16
|
+
txt2ebook/formats/typ.py,sha256=eqh9kc5FxxKr06mOmdjl8nzAjrawY4ecxbqKH86QuQQ,8208
|
17
17
|
txt2ebook/formats/templates/__init__.py,sha256=f3K7pJByNmmvu-wvziks6qb2QnnLmkDjUACXyw2s60E,760
|
18
18
|
txt2ebook/formats/templates/epub/__init__.py,sha256=-XVLvnknTJTmQZY9UTH705vMcHgy56rQVRTusYawEZ4,766
|
19
19
|
txt2ebook/helpers/__init__.py,sha256=c2EItHvPABDORfgfjArfa5XR--43es4D1tKWqaPcBxY,1309
|
@@ -29,15 +29,15 @@ txt2ebook/subcommands/__init__.py,sha256=ldhzvsrMsR8lZmhZef77JFz0jValpV3pytFfwJS
|
|
29
29
|
txt2ebook/subcommands/env.py,sha256=gEzra4b6guy7pRZUTCWX1_eiR7JmrtR1Z-J-vxljvMY,1549
|
30
30
|
txt2ebook/subcommands/epub.py,sha256=oVk00rypqN53UAOIYhOofkAPbjrdlvkszLDIdVqexvE,4706
|
31
31
|
txt2ebook/subcommands/gmi.py,sha256=ANnPg-RFsylTo44fUzFOSHN1fC3Ce82gBzrv-sBv5fU,3318
|
32
|
-
txt2ebook/subcommands/massage.py,sha256=
|
32
|
+
txt2ebook/subcommands/massage.py,sha256=WmHHJQLowdjSDQnEqxVKsU9YsabY7fw4mBkfddsFZpI,15535
|
33
33
|
txt2ebook/subcommands/md.py,sha256=PmIqrqrnzLywvN4qTkle0V9N3FTIJGRWpC0Xbk76B5o,3329
|
34
34
|
txt2ebook/subcommands/parse.py,sha256=xjhW8I9zS5DL3n3m04RyFofgci-6-_L6aF3d4N7c7M4,2938
|
35
35
|
txt2ebook/subcommands/pdf.py,sha256=1JQtpugzAIaho6G3CK1rGYk74hotAexXZxPH9PHpRps,2980
|
36
36
|
txt2ebook/subcommands/tex.py,sha256=8XqTV5GsOEr7sGSLUJB-B1KefIMxW3_BDq_Jm96Bt1Y,4369
|
37
37
|
txt2ebook/subcommands/typ.py,sha256=xeJ_cPmyq_uouUBiH2kbcscckHLqewPmu9j0WO36sXY,4814
|
38
|
-
txt2ebook-0.1.
|
39
|
-
txt2ebook-0.1.
|
40
|
-
txt2ebook-0.1.
|
41
|
-
txt2ebook-0.1.
|
42
|
-
txt2ebook-0.1.
|
43
|
-
txt2ebook-0.1.
|
38
|
+
txt2ebook-0.1.158.dist-info/licenses/LICENSE.md,sha256=tGtFDwxWTjuR9syrJoSv1Hiffd2u8Tu8cYClfrXS_YU,31956
|
39
|
+
txt2ebook-0.1.158.dist-info/METADATA,sha256=7gQjnlwM3PxI1mBQ7qsGT8k97A7nbdxAhwYlYrU0LdI,5295
|
40
|
+
txt2ebook-0.1.158.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
41
|
+
txt2ebook-0.1.158.dist-info/entry_points.txt,sha256=3jm5vpUsDRgoM6S3CQVMMiP7tJQqfq1vfV0sh_KaK9s,74
|
42
|
+
txt2ebook-0.1.158.dist-info/top_level.txt,sha256=pesdk4CJRlfhUXVD9vH3Dd_F8ATlLQoqlUsUnU8SJMw,10
|
43
|
+
txt2ebook-0.1.158.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|