diff --git a/.github/pages.md b/.github/pages.md index a5e3f0a..6453960 100644 --- a/.github/pages.md +++ b/.github/pages.md @@ -1,25 +1,23 @@ # Deploy pages workflows -Updates to the `mkdocs.yml` file or any file in the `docs` directory trigger one of two GitHub Actions workflows. -These workflows keep the deployed version of the documentation site up to date with the document files in the `main` branch. +When you update the `mkdocs.yml` file or any file in the `docs` folder, you trigger one of two GitHub Actions workflows. These workflows keep the deployed version of the documentation site up to date with the documents in the `main` branch. -Both workflows triggers workflow called `deploy-pages.yml`. This workflow runs the `mkdocs gh-deploy` command. -To make sure that the command only pushes the most recent version of the docs, there is a concurrency lock on this workflow. -The lock cancels running actions and launches a new one when it's triggered. +Both workflows triggers a workflow called `deploy-pages.yml`. This workflow runs the `mkdocs gh-deploy` command. To make sure that the command only pushes the most recent documentation, the workflow has a concurrency lock. The lock cancels any running actions and launches a new one when it's triggered. ## auto-deploy-pages This workflow runs when a pull request has met the following criteria: -- It has been merged into the `main` branch. -- It includes changes to the `mkdocs.yml` file or any file in the `docs` directory. +* It has been merged into the `main` branch. +* It includes changes to the `mkdocs.yml` file or any file in the `docs` directory. ## man-deploy-pages -This workflow runs when there a push meets the following criteria: +This workflow runs when a direct push meets the following criteria: -- It is to the `main` branch. -- It includes changes to the `mkdocs.yml` file or any file in the `docs` directory. +* It is to the `main` branch. +* It includes changes to the `mkdocs.yml` file or any file in the `docs` directory. -You can also trigger this flow manually using the -[GitHub Actions extension](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-github-actions) in VS Code. +To trigger this flow manually, use the [GitHub Actions extension][1] in VS Code. + +[1]: https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-github-actions diff --git a/.github/workflows/auto-deploy-pages.yml b/.github/workflows/auto-deploy-pages.yml index 9ce1a5f..f613f2d 100644 --- a/.github/workflows/auto-deploy-pages.yml +++ b/.github/workflows/auto-deploy-pages.yml @@ -2,7 +2,7 @@ name: deploy-pages-from-pr on: pull_request: - branches: main + branches: [main] types: ["closed"] paths: ["docs/**", "mkdocs.yml"] diff --git a/.github/workflows/man-deploy-pages.yml b/.github/workflows/man-deploy-pages.yml index e993922..0a96ed5 100644 --- a/.github/workflows/man-deploy-pages.yml +++ b/.github/workflows/man-deploy-pages.yml @@ -2,7 +2,7 @@ name: deploy-pages-from-push on: push: - branches: main + branches: [main] paths: ["docs/**", "mkdocs.yml", ".github/workflows/**"] workflow_dispatch: diff --git a/.gitignore b/.gitignore index 51db6cc..77995d1 100644 --- a/.gitignore +++ b/.gitignore @@ -166,6 +166,7 @@ cython_debug/ *.pdf *.pptx *.ppt +!**requirements.txt #ffmpeg metadata -ffmetada \ No newline at end of file +ffmetada diff --git a/backend_audio/ffmetadata_generator.py b/backend_audio/ffmetadata_generator.py index 7ea76e2..a59f70a 100644 --- a/backend_audio/ffmetadata_generator.py +++ b/backend_audio/ffmetadata_generator.py @@ -1,8 +1,12 @@ #!/usr/bin/python3 +""" +Generate metadata for audio files. +""" __doc__ = """ Goal: generate metadata to inject in m4b format file """ from tinytag import TinyTag +from typing import Optional def __get_ffmetadata1(**kwargs) -> str: isok = (kwargs['title'] is not None) or (kwargs['author'] is not None) @@ -25,18 +29,20 @@ def __get_track_times(input_audio_paths:list) -> list: starttimes.append(str(int(time))) return starttimes -def generate_ffmetadata(input_audio_paths:list, - chapter_titles:list=None, +def generate_ffmetadata(input_audio_paths:list[str], + chapter_titles:Optional[list[str]]=None, author:str=None, title:str=None) -> str: """Generate metadata in ffmpeg format. Arguments: - input_audio_paths: List[str] - path of audiable files - chapter_titles: List[str] - name of chapters defined on each files + input_audio_paths: Path of audio files + chapter_titles: Name of chapters in each file + author: The original document's author + title: The original document's title Returns: - metadata: str + metadata: The generated audio file metadata """ starttimes=__get_track_times(input_audio_paths) if chapter_titles is None: diff --git a/backend_audio/m4b.py b/backend_audio/m4b.py index 1d846ad..956742a 100644 --- a/backend_audio/m4b.py +++ b/backend_audio/m4b.py @@ -1,6 +1,7 @@ -"""Module aim to generate audio and the file result in M4B """ -from typing import List, Callable, Dict, Any +Generate audio and save it to a M4B or MP3 file. +""" +from typing import Callable, Any import logging import sys import time @@ -25,48 +26,51 @@ logger = logging.getLogger(__name__) def get_back_end_tts() -> str: - """Get the TTS engine for the system's operating system. - + """Get the TTS API for the system's operating system. + Returns: - The string name of the engine used for the caller's operating system. + back_end_tts: The name of the API that the caller's operating system uses. """ os_engine_map = { "win32": "EDGE_TTS", "cygwin": "EDGE_TTS", "darwin": "GTTS" } - return os_engine_map.get(sys.platform, "PYTTS") + back_end_tts = os_engine_map.get(sys.platform, "PYTTS") + return back_end_tts + +async def get_voices_edge_tts(lang:Optional[str]=None) -> list[dict[str, Any]]: + """Get the female voice in target language from EDGE-TTS. -async def get_voices_edge_tts(lang:str=LANGUAGE_DICT["it"]) -> List[Dict[str, Any]]: - """get FEMALE voices in target language from EDGE-TTS. - Arguments: - lang: The desired language abbreviation. - + lang: The desired language abbreviation. See [Internet Engineering Task Force (IETF) language codes](https://en.wikipedia.org/wiki/IETF_language_tag) for accepted abbreviations. + Returns: ret: A list of matching voice mappings based on lang. """ + if lang is None: + lang = LANGUAGE_DICT['it'] try: vs = await edge_tts.VoicesManager.create() ret = vs.find(Gender="Female", Language=lang) except Exception: #TODO add a best exception handling #pylint: disable=W0511,W0718 ret = [] return ret + async def generate_audio_edge_tts(text_in:str, out_mp3_path:str, *, lang:str="it", # pylint: disable=W0613 voice:str) -> bool: - """Generate audio with EDGE-TTS starting from text_in string - and save it in out_mp3_path path. - + """Generate audio with EDGE-TTS and save it to `out_mp3_path`. + Arguments: text_in: The text used to generate the TTS. - out_mp3_path: The path to save the result MP3 file. - lang: The desired language abbreviation. - voice: The TTS engine voice ID. + out_mp3_path: The path to save the MP3 file to. + lang: The desired language abbreviation. See [Internet Engineering Task Force (IETF) language codes](https://en.wikipedia.org/wiki/IETF_language_tag) for accepted abbreviations. + voice: The TTS API voice ID. Returns: - True if the function succesfully saves the MP3 file. + result: True if the function succesfully saves the MP3 file. """ com = edge_tts.Communicate(text_in, voice) await com.save(out_mp3_path) @@ -105,15 +109,15 @@ def __save_tts_audio_gtts(text_to_speech_str:str, mp3_path:str, lang:str) -> boo return True def generate_audio_gtts(text_in:str, out_mp3_path:str, *, lang:str="it") -> bool: - """Generate audio using GTTS apis. - + """Generate audio using GTTS APIs and save it to `out_mp3_path`. + Arguments: text_in: The text used to generate the TTS. - out_mp3_path: The path to save the result MP3 file. - lang: The desired language abbreviation. + out_mp3_path: The path to save the MP3 file to. + lang: The desired language abbreviation. See [Internet Engineering Task Force (IETF) language codes](https://en.wikipedia.org/wiki/IETF_language_tag) for accepted abbreviations. Returns: - True if the function succesfully saves the MP3 file. + result: True if the function succesfully saves the MP3 file. """ chunks = __split_text_into_chunks(text_in) if len(chunks)>1: @@ -123,15 +127,15 @@ def generate_audio_gtts(text_in:str, out_mp3_path:str, *, lang:str="it") -> bool return True def generate_audio_pytts(text_in:str, out_mp3_path:str, *, lang:str="it") -> bool: - """Generate audio using PYTTS apis. + """Generate audio using PYTTS APIs and save it to `out_mp3_path`. Arguments: text_in: The text used to generate the TTS. - out_mp3_path: The path to save the result MP3 file. - lang: The desired language abbreviation. + out_mp3_path: The path to save the MP3 file to. + lang: The desired language abbreviation. See [Internet Engineering Task Force (IETF) language codes](https://en.wikipedia.org/wiki/IETF_language_tag) for accepted abbreviations. Returns: - True if the function succesfully saves the MP3 file. + result: True if the function succesfully saves the MP3 file. """ if engine_ptts.getProperty("voice") != lang: engine_ptts.setProperty("voice", LANGUAGE_DICT_PYTTS[lang]) @@ -152,15 +156,15 @@ def __sub_audio(audio_generator:Callable[[str, str], bool], out = ffmpeg.output(dummy_concat, output_path_mp3, f='mp3') out.run() -def generate_m4b(output_path: str, chapter_paths: List[str], +def generate_m4b(output_path: str, chapter_paths: list[str], ffmetadata: str, pause_duration:int=0) -> None: - """Generate the final audiobook starting from MP3s and METADATAs. - + """Generate the final audiobook from MP3s and metadata. + Arguments: - output_path: The path to save the final audiobook. + output_path: The path to save the final audiobook to. chapter_paths: The paths where each chapter was saved. - ffmetadata: The ffmetadata file content. - pause_duration: the time pass between chapters, by default no pause + ffmetadata: The `ffmetadata` file content. + pause_duration: The duration of pauses between chapters. By default, there is no pause between chapters. """ silence = None if pause_duration > 0: @@ -183,11 +187,14 @@ def generate_m4b(output_path: str, chapter_paths: List[str], raise e def init(backend:str) -> None: - """Init back end code per text-to-speech - SUPPORTED: EDGE_TTS, PYTTS, GTTS. - + """Init back end code for one of the following text-to-speech APIs: + + * EDGE_TTS + * PYTTS + * GTTS + Arguments: - backend: The string name of the TTS engine. + backend: The name of the TTS API. """ global engine_ptts #pylint: disable=W0603 global voice_edge #pylint: disable=W0603 @@ -205,14 +212,15 @@ def init(backend:str) -> None: def generate_audio(text_in:str, out_mp3_path:str, *, lang:str="it", backend:str="PYTTS") -> bool: - """Generating audio using tts apis. + """Generating audio with a TTS API. + Arguments: text_in: The text used to generate the TTS. - out_mp3_path: The path to save the result MP3 file. - lang: The desired language abbreviation. - backend: The string name of the TTS engine. + out_mp3_path: The path to save the MP3 file to. + lang: The desired language abbreviation. See [Internet Engineering Task Force (IETF) language codes](https://en.wikipedia.org/wiki/IETF_language_tag) for accepted abbreviations. + backend: The name of the TTS API. Returns: - True if the function succesfully saves the MP3 file. + result: True if the function succesfully saves the MP3 file. """ ret_val = True text_in = text_in.strip() @@ -229,12 +237,19 @@ def generate_audio(text_in:str, out_mp3_path:str, *, return ret_val def close_edge_tts() -> None: - """Need to close the async io process.""" + """Close the async IO process.""" global loop #pylint: disable=W0603,W0602 if loop: loop.close() def add_cover_to_audiobook(audio_path: str, cover_path: str, output_path: str) -> None: + """Add a cover image to an audiobook. + + Arguments: + audio_path: The path to the MP3 file. + cover_path: The path to the cover image file. + output_path: The path to save the result to. + """ import subprocess command = [ 'ffmpeg', @@ -251,4 +266,4 @@ def add_cover_to_audiobook(audio_path: str, cover_path: str, output_path: str) - subprocess.run(command, check=True) if __name__ == "__main__": - add_cover_to_audiobook("../Don Giovanni.m4b", "../cover.jpg", "out.m4b") \ No newline at end of file + add_cover_to_audiobook("../Don Giovanni.m4b", "../cover.jpg", "out.m4b") diff --git a/docs/about/license.md b/docs/about/license.md index b20c129..03f2462 100644 --- a/docs/about/license.md +++ b/docs/about/license.md @@ -3,6 +3,8 @@ title: License description: Copyright information for the Write2Audiobook project. --- + + Copyright information for the Write2Audiobook project. ## Included projects @@ -33,3 +35,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/docs/how-to-contribute-to-docs.md b/docs/how-to-contribute-to-docs.md index e72351e..48739e9 100644 --- a/docs/how-to-contribute-to-docs.md +++ b/docs/how-to-contribute-to-docs.md @@ -1,15 +1,13 @@ # How to contribute to the Write2Audiobook documentation -The Write2Audiobook documentation is built with [Mkdocs](https://github.com/mkdocs/mkdocs/tree/master) and -the [Materials](https://github.com/squidfunk/mkdocs-material/tree/master) theme. These tools use simple Markdown -with a handful of extensions to create a suite of static sites. +The Write2Audiobook documentation uses [Mkdocs](https://github.com/mkdocs/mkdocs/tree/master) and the [Materials](https://github.com/squidfunk/mkdocs-material/tree/master) theme. These tools use Markdown with extensions to create static sites. -For reference material when writing Markdown, see [Material's reference page](https://squidfunk.github.io/mkdocs-material/reference/). +To learn how to write Markdown, see [Material's reference page](https://squidfunk.github.io/mkdocs-material/reference/). -Test your changes locally before submitting a pull request. +Test your changes locally before you submit a pull request. ```console -python3 -m pip install docs/requirements +python3 -m pip install -r docs/requirements.txt mkdocs serve ``` @@ -17,14 +15,11 @@ mkdocs serve ### Write documentation in Visual Studio Code with Markdown extensions -Documentation written with the `markdownlint` VS Code extension will be more consistent with varying writers. - -There is a `.markdownlint.rc` file in the project's root that helps enforce consistency. +Use the `markdownlint` VS Code extension to write documentation. The extension and the `.markdownlint.rc` file in the project's root folder help enforce consistency between writers. ### Use front matter -Each page should have a `title` and `description` tag in its front matter. -This adds useful metadata to the generated HTML header. +Add a `title` and `description` tag in each page's front matter. This adds useful metadata to the generated HTML header. ```yaml --- @@ -33,20 +28,19 @@ description: The description of the page. --- ``` -### Don't use the single `#` header level. +### Don't use the single `#` header level -The title of the page comes from the YAML front matter. Having a second first level heading is redundant. +The title of the page comes from the YAML front matter. A second first level heading is redundant. ### Sections go in their own directory -Keep each section in a single directory. You can have subdirectories if you have subsections. -This keeps the documentation folder organized. +Keep each section in a single directory. Use subdirectories if you have subsections. This keeps the documentation folder organized. ### Functions and modules have consistent docstrings The `mkdocstrings` plugin requires a consistent docstring format. -Module-level docstrings appear at the top of the page in mkdocs. They should follow this format: +Module-level docstrings appear at the top of the page in mkdocs. In a Python script, use this format: ```python """ @@ -59,7 +53,7 @@ Example usage: """ ``` -Function-level docstrings appear under their function names in mkdocs. They should follow this format: +Function-level docstrings appear under their function names in mkdocs. In a Python script, use this format: ```python def my_function(arg1: str) -> int: @@ -70,4 +64,4 @@ def my_function(arg1: str) -> int: Returns: Define what the function returns. -``` \ No newline at end of file +``` diff --git a/docs/index.md b/docs/index.md index b647e60..96e72a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,9 +3,17 @@ title: Welcome to Write2Audiobook description: Home page for Write2Audiobook project documentation. --- -Write2Audiobook is a powerful tool that converts EPUB, TXT, PPT, and DOCX documents into engaging audiobooks directly -from the command-line. This tool is perfect for making reading more accessible for people with visual impairments and -for those who simply prefer listening on the go. +Write2Audiobook is a powerful tool that converts text files into audio files from a command-line interface (CLI). This tool aims to make reading more accessible to people with visual impairments and for those who prefer the audio format. -To see Write2Audiobook in action, check out the [Quick start guide](quick-start.md). Then go to the -[User guide](./user-guide/index.md) to learn more. +Use this tool to convert the following document types into audio files: + +* Ebooks +* Plain text files +* PDF files +* Microsoft PowerPoint presentations +* Microsoft Word documents + +To learn how to use Write2Audiobook, see the [Quick start guide][1]. For more detailed reference information, see the [User guide][2]. + +[1]: quick-start.md +[2]: ./user-guide/index.md diff --git a/docs/quick-start.md b/docs/quick-start.md index bc4d57e..753dafa 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -7,47 +7,55 @@ Follow this tutorial to learn how to use Write2Audiobook. ## Prerequisites -Before you begin, download and install the required files. +Before you begin: -Learn more about [downloading the scripts from GitHub](./user-guide/download-scripts.md) and [installing the required packages](./user-guide/install-libraries.md). +1. [Download the scripts from GitHub][1] +1. [Install the required packages][2] -## Convert a text-based file to an audiobook +## Convert a text file to an audio file -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. Clone the Write2Audiobook repo and go to the project's root directory. ```console + git clone https://github.com/deangelisdf/write2audiobook.git cd write2audiobook ``` -1. Run one of the scripts to convert a text-based file to an audiobook: - To convert an Ebook (EPUB) to an audiobook: +1. Run one of the scripts to convert a text file to an audio file. - ```console - python3 ebook2audio.py book.epub - ``` + * To convert an ebook (`.epub`) to an English-language audio file: - To convert a plain text file to an audiobook: + ```console + python3 ebook2audio.py book.epub en + ``` - ```console - python3 txt2audio.py text.txt - ``` + * To convert a plain text file (`.txt`) to an English-language audio file: - To convert a PowerPoint presentation (PPTX) to an audiobook: + ```console + python3 txt2audio.py text.txt en + ``` - ```console - python3 pptx2audio.py presentation.pptx - ``` + * To convert a Microsoft PowerPoint presentation (`.pptx`) to an English-language audio file: - To convert a Word document (DOCX) to an audiobook: + ```console + python3 pptx2audio.py presentation.pptx en + ``` - ```console - python3 docx2audio.py document.docx - ``` + * To convert a Microsoft Word document (`.doc` or `.docx`) to an English-language audio file: -## Play your audiobook + ```console + python3 docx2audio.py document.docx en + ``` -Write2Audio saves your audiobook as an audio file in the current directory. It will have the same name as the converted file. +## Play the audio file + +Write2Audio saves your audio file in the current directory. It has the same name as the converted file, but with a `.mp3` extension. ![directory-image](img/example-output.png) -You can listen to your audiobook with any program that can open MP3 or M4B files, like [VLC](https://www.videolan.org/vlc/). +Listen to your audiobook with any program that can open MP3 or M4B files, like [VLC][3]. + +[1]: ./user-guide/download-scripts.md +[2]: ./user-guide/install-libraries.md +[3]: https://www.videolan.org/vlc/ diff --git a/docs/reference/pdf2audio.md b/docs/reference/pdf2audio.md new file mode 100644 index 0000000..87830c1 --- /dev/null +++ b/docs/reference/pdf2audio.md @@ -0,0 +1,8 @@ +--- +title: pdf2audio +description: Functions defined in the pdf2audio script. +--- + +This page describes the functions in the `pdf2audio` script. + +::: pdf2audio diff --git a/docs/requirements b/docs/requirements deleted file mode 100644 index 0a3e335..0000000 --- a/docs/requirements +++ /dev/null @@ -1,3 +0,0 @@ -pymdown-extensions -mkdocs-material -mkdocstrings-python \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..e158cf6 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +pymdown-extensions +mkdocs-material +mkdocstrings-python +mkdocs-git-revision-date-localized-plugin diff --git a/docs/user-guide/docx-to-audio.md b/docs/user-guide/docx-to-audio.md index 46e4773..0b41682 100644 --- a/docs/user-guide/docx-to-audio.md +++ b/docs/user-guide/docx-to-audio.md @@ -3,40 +3,51 @@ title: Word documents description: Instructions on converting Word documents to MP3. --- -This page explains how to use the `docx2audio.py` script to convert Word documents to MP3 files. +This page explains how to convert a Microsoft Word document to audio files. !!! important - Word documents you want to convert must meet these requirements: - - * The file extension must be **.docx**. + The document's extension must be `.doc` or `.docx`. ## Run the script -To convert a Word document to MP3 files: +To convert a Microsoft Word document to audio files: -1. [Download the script](./download-scripts.md) and [install the required libraries](./install-libraries.md). -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. [Download the scripts][1]. +1. [Install the required libraries][2]. +1. Run the `docx2audio.py` script. ```console - cd write2audiobook + python3 docx2audio.py .docx ``` -1. Run the `docx2audio.py` script. +
+
<PATH_TO_FILE>
+
The full path to the Microsoft Word document that you want to convert to audio files.
+
<LANGUAGE>
+
The desired output language's [Internet Engineering Task Force (IETF) language tag][3]. For example, English's tag is `en`.
+
- ```console - python3 docx2audio.py path/to/file/test.docx - ``` +This saves audio files in the current folder. ## View the output -The script creates MP3 files and plain text files as it converts the Word document. It may convert -larger documents into multiple MP3 files and text files. +The script creates MP3 files and plain text files as it converts the Microsoft Word document. For large documents, it may create multiple MP3 files and text files. + +For example, if the script creates X number of files: -For example, if the script creates *X* files: +* MP3 files have a name like `.docx.cX.mp3` +* Text files have a name like `.docx.cX.txt` -- MP3 files will have a name like `\.docx.cX.mp3`. -- Text files will have a name like `\.docx.cX.txt` +
+
<ORIGINAL_FILE_NAME>
+
The Microsoft Word document's original name.
+
-Look for the MP3 files in the Word document's directory to confirm the conversion was successful. +Look for the MP3 files in the current folder. They have the same name as the converted file, but with a `.mp3` extension. ![docx-to-audio-output](../img/docx-to-audio-output.png) + +[1]: ./download-scripts.md#download-the-scripts +[2]: ./install-libraries.md#install-the-required-libraries +[3]: https://en.wikipedia.org/wiki/IETF_language_tag diff --git a/docs/user-guide/download-scripts.md b/docs/user-guide/download-scripts.md index a5521bf..783e348 100644 --- a/docs/user-guide/download-scripts.md +++ b/docs/user-guide/download-scripts.md @@ -7,16 +7,34 @@ This page explains how to download and update the Write2Audiobook scripts. ## Download the scripts -Download the scripts from the [Write2Audiobook GitHub repository](https://github.com/deangelisdf/write2audiobook). +Clone the [Write2Audiobook GitHub repository][1] to download the scripts: -```command -git clone https://github.com/deangelisdf/write2audiobook -``` +1. Open a terminal window. +1. Run the following command to clone the repository: + + ```command + git clone https://github.com/deangelisdf/write2audiobook.git + ``` + +This creates a folder on your computer with all the scripts. The folder's name is `write2audiobook`. ## Update the scripts -Update the scripts by pulling the latest version from the [Write2Audiobook GitHub repository](https://github.com/deangelisdf/write2audiobook). +Pull the latest version of the [Write2Audiobook GitHub repository][1] to update the scripts: + +1. Open a terminal window. +1. Go to the `write2audiobook` folder. + + ```console + cd write2audiobook + ``` + +1. Run the following command to update the scripts: + + ```command + git pull + ``` + +This replaces the scripts on your computer with the updated scripts from the repository. -```command -git pull -``` +[1]: https://github.com/deangelisdf/write2audiobook diff --git a/docs/user-guide/ebook-to-audio.md b/docs/user-guide/ebook-to-audio.md index c48dbf3..4adac67 100644 --- a/docs/user-guide/ebook-to-audio.md +++ b/docs/user-guide/ebook-to-audio.md @@ -3,40 +3,46 @@ title: Ebooks description: Instructions on converting Ebooks to MP3. --- -This page explains how to use the `ebook2audio.py` script to convert Ebooks to MP3 files. +This page explains how to convert an ebook to audio files. !!! important - Ebooks you want to convert must meet these requirements: - - * The file extension must be **.pub**. + The file's extension must be `.epub`. ## Run the script -To convert an Ebook to MP3 files: +To convert an ebook to audio files: -1. [Download the script](./download-scripts.md) and [install the required libraries](./install-libraries.md). -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. [Download the scripts][1]. +1. [Install the required libraries][2]. +1. Run the `ebook2audio.py` script. ```console - cd write2audiobook + python3 ebook2audio.py .epub ``` -1. Run the `ebook2audio.py` script. +
+
<PATH_TO_FILE>
+
The full path to the text file that you want to convert to an audio file.
+
<LANGUAGE>
+
The desired output language's [Internet Engineering Task Force (IETF) language tag][3]. For example, English's tag is `en`.
+
- ```console - python3 ebook2audio.py path/to/file/test.epub - ``` +This saves audio files in the current folder. ## View the output -The script creates MP3 files and plain text files as it converts the Ebook. It may convert -larger books into multiple MP3 files and text files. +The script creates MP3 files and plain text files as it converts the ebook. For large ebooks, it may create multiple MP3 files and text files. + +For example, if the script creates X files: -For example, if the script creates *X* files: +- MP3 will have a name like `itemX.mp3`. +- Text will have a name like `itemX.log` -- MP3 files will have a name like `itemX.mp3`. -- Text files will have a name like `itemX.log` +Look for the MP3 files in the current folder. -Look for the MP3 files in the Ebook's directory to confirm the conversion was successful. +![ebook-to-audio-output](../img/ebook-to-audio-output.png) -![docx-to-audio-output](../img/ebook-to-audio-output.png) +[1]: ./download-scripts.md#download-the-scripts +[2]: ./install-libraries.md#install-the-required-libraries +[3]: https://en.wikipedia.org/wiki/IETF_language_tag diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md index 6df74ef..2d8337b 100644 --- a/docs/user-guide/index.md +++ b/docs/user-guide/index.md @@ -3,4 +3,8 @@ title: User Guide description: Index page for user guide section of Write2Audiobook's documentation. --- -After you've completed the [quick start guide](../quick-start.md), see this section for more information about each script. +If you haven't used the Write2Audiobook before, start with the [quick start guide][1]. + +Use this section to learn more information about the project and each script. + +[1]: ../quick-start.md diff --git a/docs/user-guide/install-libraries.md b/docs/user-guide/install-libraries.md index bd10fae..99d23bf 100644 --- a/docs/user-guide/install-libraries.md +++ b/docs/user-guide/install-libraries.md @@ -3,43 +3,48 @@ title: Install libraries description: Instructions on how to install the required libraries for the Write2Audiobook project. --- -This page explains how to install the libraries and packages required to run the Write2Audiobook scripts. +This page explains how to install the packages that you need to run the Write2Audiobook scripts. ## Prerequisites -All Write2Audiobook scripts are written in Python. If you don't already have Python installed on your computer, see the -[Python Beginner's Guide](https://wiki.python.org/moin/BeginnersGuide/Download) for instructions on downloading -and installing Python. +All Write2Audiobook scripts are Python scripts. To run them, you need to have Python version 3.7 or higher installed on your computer. + +Run the following command to see which Python version you have installed on your computer: + +```console +python -v +``` + +If the command doesn't work or if your Python version's too low, install a new Python version. See the [Python Beginner's Guide][1] to learn how to download and install Python. ## Virtual environments -Virtual environments keep workspaces clean and avoid potential conflicts with previously -install libraries. This keeps your development environments isolated. If something happens to -a library in a virtual environment, you've contained the damage to that one folder. +Virtual environments keep workspaces clean and isolated. They help to avoid conflicts with other libraries that you may install for other projects. If something happens to a library in a virtual environment, it keeps the damage to just one folder. That means you can uninstall any broken libraries with no impact on other workspaces. ### Create a virtual environment Create a virtual environment for your Write2Audiobook project: -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. Go to the Write2Audiobook project's root folder. ```console cd write2audiobook ``` -1. Run the following command: +1. Run the following command to create the virtual environment: ```console python3 -m venv .venv ``` - This creates a virtual environment in new folder called `.venv`. +This creates a virtual environment in new folder called `.venv`. -### Activate a virtual environment +### Activate the virtual environment -Run the following code to activate a virtual environment: +Activate the virtual environment: -=== "Powershell" +=== "PowerShell" ```powershell .venv\Scripts\Activate.ps1 ``` @@ -54,13 +59,13 @@ Run the following code to activate a virtual environment: source .venv/bin/activate ``` -When your virtual environment is active, you'll see `(.venv)` in front of your terminal's prompt. +When your virtual environment is active, you see `(.venv)` in front of your terminal's prompt. ![venv-source-example](../img/venv-source-example.png) -### Exit a virtual environment +### Exit the virtual environment -After you have finished working in the Write2Audiobook project, exit the virtual environment with the following command: +When you're done working, exit the virtual environment: ```console deactivate @@ -68,28 +73,38 @@ deactivate ## Install the required libraries -The Write2Audio project requires several Python libraries to run its scripts. The -[`requirements`](https://github.com/deangelisdf/write2audiobook/blob/main/requirements) file lists these libraries. +The Write2Audio project requires several thrid-party Python libraries. To see the list of required libraries, open the [`requirements.txt`][2] file. -Install the libraries from the `requirements` file: +Install the libraries from the `requirements.txt` file: -1. [Activate your virtual environment](#activate-a-virtual-environment). -1. Run the following command: +1. Open a terminal window. +1. Go to the Write2Audiobook project's root folder. ```console - python3 -m pip install -r requirements + cd write2audiobook ``` -1. Confirm the installation succeeded by looking at the list of installed libraries. +1. [Activate your virtual environment](#activate-the-virtual-environment). +1. Run the following command to install the required libraries: ```console - python3 -m pip list + python3 -m pip install -r requirements.txt ``` -You'll get a confirmation message when the installation is complete. +You get a confirmation message when the installation is complete. + +To see a list of the libraries you installed this way, run the following command: + +```console +python3 -m pip list + ``` !!! important - If you're on a Linux system, you must install additional system packages. Install these packages with the following command: + If you use a Linux system, you must install three additional system packages. Run the following command to install these packages: + ```console sudo apt update && sudo apt install espeak ffmpeg libespeak1 -y ``` + +[1]: https://wiki.python.org/moin/BeginnersGuide/Download +[2]: https://github.com/deangelisdf/write2audiobook/blob/main/requirements.txt diff --git a/docs/user-guide/pptx-to-audio.md b/docs/user-guide/pptx-to-audio.md index 7170583..56fea12 100644 --- a/docs/user-guide/pptx-to-audio.md +++ b/docs/user-guide/pptx-to-audio.md @@ -1,34 +1,41 @@ --- title: PowerPoint presentations -description: Instructions on converting PowerPoint presentations to MP3. +description: Instructions on converting PowerPoint presentations to M4b. --- -This page explains how to use the `pptx2audio.py` script to convert PowerPoint presentations to MP3 files. +This page explains how to convert a Microsoft PowerPoint presentations to an audio file. !!! important - PowerPoint presentations you want to convert must meet these requirements: - - * The file extension must be **.pptx**. + The presentation's extension must be `.pptx`. ## Run the script -To convert a PowerPoint presentation to an m4b file: +To convert a Microsoft PowerPoint presentation to an audio file: -1. [Download the script](./download-scripts.md) and [install the required libraries](./install-libraries.md). -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. [Download the scripts][1]. +1. [Install the required libraries][2]. +1. Run the `pptx2audio.py` script. ```console - cd write2audiobook + python3 pptx2audio.py .pptx ``` -1. Run the `pptx2audio.py` script. +
+
<PATH_TO_FILE>
+
The full path to the text file that you want to convert to an audio file.
+
<LANGUAGE>
+
The desired output language's [Internet Engineering Task Force (IETF) language tag][3]. For example, English's tag is `en`.
+
- ```console - python3 pptx2audio.py path/to/file/test.pptx - ``` +This saves an audio file in the current folder. ## View the output -Look for the mb4 file in your current directory to confirm the conversion was successful. +Look for the audio file in your current folder. It has the same name as the converted file, but with a `.m4b` extension. ![successful-conversion](../img/pptx-to-audio-output.png) + +[1]: ./download-scripts.md#download-the-scripts +[2]: ./install-libraries.md#install-the-required-libraries +[3]: https://en.wikipedia.org/wiki/IETF_language_tag diff --git a/docs/user-guide/text-to-audio.md b/docs/user-guide/text-to-audio.md index 5caeea1..2db34e3 100644 --- a/docs/user-guide/text-to-audio.md +++ b/docs/user-guide/text-to-audio.md @@ -3,33 +3,40 @@ title: Text files description: Instructions on converting plain text files to MP3. --- -This page explains how to use the `txt2audio.py` script to convert plain text files to MP3 files. +This page explains how to convert a plain text file to an audio file. !!! important - Text files you want to convert must meet these requirements: - - * The file encoding must be **UTF-8**. - * The file extension must be **.txt**. + * The text file's encoding must be **UTF-8**. + * The text file's extension must be `.txt`. ## Run the script -To convert a TXT file to an MP3 file: +To convert a text file to an audio file: -1. [Download the script](./download-scripts.md) and then [install the required libraries](./install-libraries.md). -1. In your terminal, go to the Write2Audiobook project's root directory. +1. Open a terminal window. +1. [Download the scripts][1]. +1. [Install the required libraries][2]. +1. Run the `txt2audio.py` script. ```console - cd write2audiobook + python3 txt2audio.py .txt ``` -1. Run the `txt2audio.py` script. +
+
<PATH_TO_FILE>
+
The full path to the text file that you want to convert to an audio file.
+
<LANGUAGE>
+
The desired output language's [Internet Engineering Task Force (IETF) language tag][3]. For example, English's tag is `en`.
+
- ```console - python3 txt2audio.py path/to/file/test.txt - ``` +This saves an audio file in the current folder. ## View the output -Look for the MP3 file in your current directory to confirm the conversion was successful. +Look for the MP3 file in the current folder. It has the same name as the converted file, but with a `.mp3` extension. ![successful-conversion](../img/example-output.png) + +[1]: ./download-scripts.md#download-the-scripts +[2]: ./install-libraries.md#install-the-required-libraries +[3]: https://en.wikipedia.org/wiki/IETF_language_tag diff --git a/docx2audio.py b/docx2audio.py index 67b0644..25e3348 100644 --- a/docx2audio.py +++ b/docx2audio.py @@ -1,16 +1,16 @@ #!/usr/bin/python3 """ -file: [docx2audio.py](https://github.com/deangelisdf/write2audiobook/blob/main/docx2audio.py) +[`docx2audio.py`](https://github.com/deangelisdf/write2audiobook/blob/main/docx2audio.py) -description: Convert your docx file to audiobook in MP3 format. +Convert a `.doc` or `.docx` file to MP3 files. Usage example: - `python docx2audio.py document.docx` + `python docx2audio.py document.docx en` """ import os import logging -from typing import List, Tuple, Union, Generator +from typing import Union, Generator from docx import Document from docx.document import Document as _Document from docx.oxml.text.paragraph import CT_P @@ -48,15 +48,13 @@ def iter_block_items( parent:Union[Document, _Cell, _Row] ) -> Generator[Union[Paragraph, Table], None, None]: """ - Generate a reference to each paragraph and table child within *parent*, - in document order. Each returned value is an instance of either Table or - Paragraph. *parent* would most commonly be a reference to a main - Document object, but also works for a _Cell object, which itself can - contain paragraphs and tables. + Create a reference to each paragraph and table within a section + in document order. Each returned value is either a Table or Paragraph object. + The `parent` object can be a Cell, Paragraph, or Table object. Arguments: - parent: The main Word document object, or an individual `_Cell` object. - + parent: The main document object or an individual `Cell` object. + Yields: A Paragraph or Table object. """ @@ -68,20 +66,20 @@ def iter_block_items( yield Table(child, parent) def extract_chapters(doc:Document, - style_start_chapter_name:Tuple[str] = TITLE_TOKENS - ) -> List[Union[Paragraph, Table]]: - """Extract chapters as list of paragraphs and table, the chapter are structured as - Title (with style like Heading1 and Title) and corpus (other styles). + style_start_chapter_name:tuple[str] = TITLE_TOKENS + ) -> list[Union[Paragraph, Table]]: + """Get chapters as a list of paragraphs and tables. The chapters comprise a + title (with Word styles like Heading1 or Title) and the corpus (with other Word styles). Arguments: doc: The main Word document item. - style_start_chapter_name: Possible identifiers for titles in the Word document. - + style_start_chapter_name: Identifiers for titles in the Word document. + Returns: - A list of Paragraph or Table objects. + result: A list of Paragraph or Table objects. """ - temp_chapters: List[List[Union[Paragraph, Table]]] = [] - temp:List[Union[Paragraph, Table]] = [] + temp_chapters: list[list[Union[Paragraph, Table]]] = [] + temp:list[Union[Paragraph, Table]] = [] for block in iter_block_items(doc): if isinstance(block, Paragraph): if block.style.name in style_start_chapter_name: @@ -94,15 +92,16 @@ def extract_chapters(doc:Document, return [i for i in temp_chapters if len(i)>0] def get_text_from_paragraph(block: Paragraph, language:str, - idx_list:int) -> Tuple[str, int]: - """Generate text starting from Paragraph object + idx_list:int) -> tuple[str, int]: + """Get text from a Paragraph object. + Arguments: - block (Table) - language (str) - idx_list (int) + block: The Paragraph object to get text from. + language: The language of the Paragraph object's content. + idx_list: The current count of Paragraph objects. Return: - str: table text - idx_list + text: The Paragraph object's content. + idx_list: The Paragraph's location in the original document. """ text = "" if block.style.name == LIST_ITEM_TOKEN: @@ -116,12 +115,13 @@ def get_text_from_paragraph(block: Paragraph, language:str, return text, idx_list def get_text_from_table(block: Table, language:str) -> str: #pylint: disable=W0613 - """Generate text starting from Table object + """Get text from a Table object. + Arguments: - block (Table) - language (str) + block: The Table object to get text from. + language: The language of the Table object's content. Return: - str: table text + text: The Table object's content """ text = "" for row in block.rows: @@ -132,17 +132,16 @@ def get_text_from_table(block: Table, language:str) -> str: #pylint: disable=W06 text += "{}\n".format('\t'.join(row_data)) return text -def get_text_from_chapter(chapter_doc:List[Union[Paragraph, Table]], - language:str=LANGUAGE) -> Tuple[str, str]: - """Generate an intermediate representation in textual version, - starting from docx format to pure textual, adding sugar context information. +def get_text_from_chapter(chapter_doc:list[Union[Paragraph, Table]], + language:str=LANGUAGE) -> tuple[str, str]: + """Get text from a chapter in the original document. Arguments: - chapter_doc: A list of Paragraphs and Tables. - language: The desired language abbreviation. + chapter_doc: A list of Paragraph and Table objects. + language: The language of the chapter's content. Returns: - A tuple of the object's title and its text content. + result: A tuple of the object's title and its text content. """ title_str = chapter_doc[0].text text = f"{TITLE_KEYWORD[language]}: {title_str}.\n" @@ -156,11 +155,10 @@ def get_text_from_chapter(chapter_doc:List[Union[Paragraph, Table]], return text, title_str def main(): - """main function""" in_file_path, out_file_path, language = input_tool.get_sys_input(os.path.dirname(__file__)) chapters = [] - chapters_path: List[str] = [] - title_list:List[str] = [] + chapters_path: list[str] = [] + title_list:list[str] = [] m4b.init(BACK_END_TTS) diff --git a/ebook2audio.py b/ebook2audio.py index 3c1db60..ad797b2 100644 --- a/ebook2audio.py +++ b/ebook2audio.py @@ -1,11 +1,11 @@ #!/usr/bin/python3 """ -file: [ebook2audio.py](https://github.com/deangelisdf/write2audiobook/blob/main/ebook2audio.py) +[`ebook2audio.py`](https://github.com/deangelisdf/write2audiobook/blob/main/ebook2audio.py) -description: Convert your epub file to audiobook in MP3 format. +dConvert a `.epub` file to MP3 files. Usage example: - `python ebook2audio.py book.epub` + `python ebook2audio.py book.epub en` """ import zipfile @@ -13,7 +13,6 @@ import os import logging import codecs -from typing import Dict, Tuple, List from lxml import etree from backend_audio import m4b from backend_audio import ffmetadata_generator @@ -29,24 +28,24 @@ "copyright"] def extract_by_epub(epub_path: str, directory_to_extract_path: str) -> None: - """Unzip the epub file and extract all in a temp directory. + """Unzip the `epub` file to a temporary folder. Arguments: - epub_path: The path to the epub file. - directory_to_extract_path: The temp directory to extract epub file to. + epub_path: The path to the `epub` file. + directory_to_extract_path: The temporary folder to unzip `epub` file to. """ logger.debug("Extracting input to temp directory %s.", directory_to_extract_path) with zipfile.ZipFile(epub_path, 'r') as zip_ref: zip_ref.extractall(directory_to_extract_path) -def get_guide_epub(root_tree: etree.ElementBase) -> Dict[str, str]: - """Get information about the guide information, described in content.opf file. +def get_guide_epub(root_tree: etree.ElementBase) -> dict[str, str]: + """Get the guide information from the `content.opf` file. Arguments: - root_tree: The base of the XML tree in epub contents. + root_tree: The XML tree's base from the `epub` file's content. Returns: - A map of the guide XML node types and their hyperlink content. + guide_res: A map of the guide XML node types and their hyperlink content. """ guide_res = {} for reference in root_tree.xpath("//*[local-name()='package']" @@ -56,13 +55,13 @@ def get_guide_epub(root_tree: etree.ElementBase) -> Dict[str, str]: return guide_res def prepocess_text(text_in: str) -> str: - """Remove possibly non-audible characters. + """Remove non-audible characters. Arguments: - text_in: The epub file's text. + text_in: The raw `epub` file's content. Returns: - The processed epub file's text. + text_out: The processed `epub` file's content. """ text_out = codecs.decode(bytes(text_in, encoding="utf-8"), encoding="utf-8") text_out = text_out.replace('\xa0', '') @@ -72,18 +71,17 @@ def prepocess_text(text_in: str) -> str: def get_text_from_chapter(root_tree: etree._ElementTree, idref_ch : str, content_dir_path: str, - guide_manifest: Dict[str,str]) -> Tuple[str, Dict[str,str]]: - """Starting from content.opf xml tree, extract chapter html path - and parse it to achieve the chapter. - + guide_manifest: dict[str,str]) -> tuple[str, dict[str,str]]: + """Use the `content.opf` XML tree to read and parse a chapter's HTML path. + Arguments: - root_tree: The base of the XML tree in epub contents. - idref_ch: The XML ID of the chapter. + root_tree: The XML tree's base from the `epub` file's content. + idref_ch: The chapter's XML ID. content_dir_path: The path to the XML file. guide_manifest: A map of the guide XML node types and their hyperlink content. Returns: - A tuple of the chapter's text and an empty dictionary. + text_result: A tuple of the chapter's text and an empty dictionary. """ text_result = "" for href in root_tree.xpath(f"//*[local-name()='package']" @@ -100,14 +98,14 @@ def get_text_from_chapter(root_tree: etree._ElementTree, text_result += '\n'.join(text for text in ptag.itertext()) return text_result, {} -def get_metadata(root_tree: etree._ElementTree) -> Dict[str,str]: - """Extract basic metadata, as title, author and copyrights infos from content.opf. +def get_metadata(root_tree: etree._ElementTree) -> dict[str,str]: + """Get basic metadata, like title, author and copyright information, from the `content.opf` file. Arguments: - root_tree: The base of the XML tree in epub contents. + root_tree: The XML tree's base from the `epub` file's content. Returns: - A mapping of node titles and their vlaues from the root_tree. + metadata_result: A map of node titles and their values from the XML tree's base. """ metadata_leaf = root_tree.xpath("//*[local-name()='package']/*[local-name()='metadata']")[0] metadata_result = {"title":"", "author":""} @@ -132,19 +130,20 @@ def extract_chapter_and_generate_mp3(tree: etree._ElementTree, #pylint: disable output_file_path:str, mp3_temp_dir:str, content_file_dir_path:str, - guide:Dict[str,str], - language:str) -> List[str]: - """Extract id reference from container.xml file and extract chapter text. + guide:dict[str,str], + language:str) -> list[str]: + """Get a chapter's ID reference and text from the `container.xml` file. Arguments: - tree: The base of the XML tree in epub contents. - output_file_path: The path to save the result MP3 file. - mp3_temp_dir: The temporary directory path to save MP3 files as the XML tree is parsed. + tree: The XML tree's base from the `epub` file's content. + output_file_path: The path to save the MP3 file to. + mp3_temp_dir: The temporary folder to save MP3 files to as the function parses the XML tree. content_file_dir_path: The path to the XML file. guide: A map of the guide XML node types and their hyperlink content. + language: The content's language. Returns: - A list of the saved MP3 file paths. + chapters: A list of the saved MP3 file paths. """ chapters = [] for idref in tree.xpath("//*[local-name()='package']" @@ -171,10 +170,9 @@ def extract_chapter_and_generate_mp3(tree: etree._ElementTree, #pylint: disable return chapters def main(): - """main function""" tool_path: str = os.path.dirname(__file__) in_file_path, out_file_path, language = input_tool.get_sys_input(tool_path) - chapters: List[str] = [] + chapters: list[str] = [] m4b.init(BACK_END_TTS) with tempfile.TemporaryDirectory() as tmp_dir: diff --git a/frontend/input_tool.py b/frontend/input_tool.py index bbffd69..6dacb9f 100644 --- a/frontend/input_tool.py +++ b/frontend/input_tool.py @@ -1,37 +1,36 @@ """ -file: input_file.py -description: handling of external input +Handles user input. """ import sys import logging import argparse import os from pathlib import Path -from typing import Tuple logger = logging.getLogger(__name__) SUPPORTED_LANGUAGE = ["it", "en"] def get_path(path: str) -> Path: - """ - parses the path to a file given by user input + """Get a file path if it exists. + + Arguments: + path: The path to the file to convert. """ if not os.path.exists(path): logger.error("file to read %s does not exist", path) sys.exit(1) return Path(path) -def get_sys_input(main_path:str, format_output:str="m4b") -> Tuple[str, str, str]: +def get_sys_input(main_path:str, format_output:str="m4b") -> tuple[str, str, str]: """Get input and output path files. Arguments: - main_path: The path of the calling script. + main_path: The path of the script that calls this function. format_output: The format to save the result file as. Returns: - A tuple of the file supplied by the user at the - command-line and the path the result file is saved to. + result: A tuple that comprises the path to the file to convert, the path to save the converted file to, and the language abbreviation of the converted audio file. """ argparser = argparse.ArgumentParser( usage='usage: %(prog)s ', diff --git a/mkdocs.yml b/mkdocs.yml index f7d5c7a..731f54d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -38,6 +38,7 @@ nav: - ebook2audio: reference/ebook2audio.md - pptx2audio: reference/pptx2audio.md - txt2audio: reference/txt2audio.md + - pdf2audio: reference/pdf2audio.md - About: - Release Notes: about/release-notes.md - Contributing: about/contributing.md @@ -56,6 +57,7 @@ markdown_extensions: plugins: - search + - git-revision-date-localized - mkdocstrings: default_handler: python handlers: diff --git a/pdf2audio.py b/pdf2audio.py index ffbe45b..ba8529a 100644 --- a/pdf2audio.py +++ b/pdf2audio.py @@ -1,11 +1,15 @@ #!/usr/bin/python3 """ -file: [pdf2audio.py](https://github.com/deangelisdf/write2audiobook/blob/main/pdf2audio.py) +[`pdf2audio.py`](https://github.com/deangelisdf/write2audiobook/blob/main/pdf2audio.py) -description: Convert your pdf to audiobook in MP3 format. +Convert a `.pdf` file to an MP3 file. Usage example: - `python pdf2audio.py document.pdf` + `python pdf2audio.py document.pdf en` + +!!! warning + This module is experimental. + """ import os import re @@ -22,8 +26,15 @@ PATTERN_REFERENCE_STR = r"\[[0-9]+(, [0-9]+)*\]|\([0-9]+(, [a-zA-Z0-9]+)+\)" REGEX_REFERENCE = re.compile(PATTERN_REFERENCE_STR) -def read_cff(cff_data): - """Decompile CFF font format""" +def read_cff(cff_data: dict) -> dict: + """Decompile CFF fonts. + + Arguments: + cff_data: The CFF font file's content. + + Returns: + cff_font_set: The top dictionary from the CFF font file's content. + """ cff_data_io = BytesIO(cff_data) cff_font_set = CFFFontSet() cff_font_set.decompile(cff_data_io, None) @@ -44,8 +55,15 @@ def __add_family_name(fonts:dict)->dict: result[font_name] = {'family-name': family_name} return result -def get_fonts(pdf_doc:utils.pymupdf.Document): - """...""" +def get_fonts(pdf_doc:utils.pymupdf.Document) -> dict: + """Get the fonts used in the original document. + + Arguments: + pdf_doc: The original PDF document. + + Returns: + fonts: A map of font names and their properties. + """ xref_visited = [] fonts = {} for page in pdf_doc: @@ -67,15 +85,27 @@ def get_fonts(pdf_doc:utils.pymupdf.Document): return fonts def filter_reference(text_with_ref:str)->str: - """remove refence from text - Args: - text_with_ref (str): the string contain all the text + """Remove a refence, like a footnote or citation, from a text segment. + + Arguments: + text_with_ref: The text segment that has a reference. + Returns: - str: the string contain all text without refences""" + result: The text segment without the reference. + """ return REGEX_REFERENCE.sub('', text_with_ref) def get_chapter_text(pdf_doc:utils.pymupdf.Document, pattern_header:str, pattern_footer:str)->list:#pylint: disable=R0914,R1260 - """...""" + """Get text from a PDF document. + + Arguments: + pdf_doc: The original PDF document. + pattern_header: A regular expression pattern that matches the PDF document's header. + pattern_footer: A regular expression pattern that matches the PDF document's footer. + + Returns: + extracted_text: The PDF document's content. + """ extracted_text = [] block_prediction = "" prev_font = None @@ -108,10 +138,16 @@ def get_chapter_text(pdf_doc:utils.pymupdf.Document, pattern_header:str, pattern prev_font = (font_name, font_size) return extracted_text -def cluster_text(raw_text:list, fonts:dict)->dict: - """Prototype, it shall organize the text extracted before - in order to have less possible instance not correlated. - desiderable: [{chapter title},{chapter text},{chapter title},...]""" +def cluster_text(raw_text:list, fonts:dict)->list: + """Groups text blocks based on their font and size. + + Arguments: + raw_text: A list of text blocks. + fonts: A map of font names and their properties. + + Returns: + clustered_text: A list of grouped text blocks. + """ clustered_text = [] print(fonts) if len(raw_text)<=1: @@ -125,18 +161,30 @@ def cluster_text(raw_text:list, fonts:dict)->dict: clustered_text.append(rtext) return clustered_text -def get_metadata(pdf_doc): #pylint: disable=W0613 - """prototype it shall take metadata by the file""" +def get_metadata(pdf_doc: utils.pymupdf.Document) -> dict[str,str]: #pylint: disable=W0613 + """Get metadata of original PDF document. + + Arguments: + pdf_doc: The original PDF document. + + Returns: + metadata: The PDF document's metadata. + """ return {"title":None, "author":None} def get_chapters(text_clustered:list)->list: - """protype it shall return a list of strings - where each one is a chapter""" + """Get a list of text grouped by chapter. + + Arguments: + text_clustered: A list of text blocks. + + Returns: + text_ret: A list of text grouped by chapter. + """ text_ret = ' '.join([i['txt'] for i in text_clustered]) return [text_ret] def main():#pylint: disable=R0914 - """main function""" in_file_path, out_file_path, language = input_tool.get_sys_input(os.path.dirname(__file__)) PATTERN_HEADER = r"arXiv:2310\.03605v3 \[cs.CR\] 29 Nov 2023" #pylint: disable=C0103 PATTERN_FOOTER = r"pag. [0-9]+Phenomena Journal \| www\.phenomenajournal.itLuglio-Dicembre 2021 \| Volume 3 \|( Numero [0-9]+ \|)? Ipotesi e metodi di studio" #pylint: disable=C0103,C0301 diff --git a/pptx2audio.py b/pptx2audio.py index 1a14158..22590ef 100644 --- a/pptx2audio.py +++ b/pptx2audio.py @@ -1,11 +1,11 @@ #!/usr/bin/python3 """ -file: [pptx2audio.py](https://github.com/deangelisdf/write2audiobook/blob/main/pptx2audio.py) +[`pptx2audio.py`](https://github.com/deangelisdf/write2audiobook/blob/main/pptx2audio.py) -description: Convert your pptx to audiobook in MP3 format. +Convert a `.pptx` file to an M4B file. Usage example: - `python pptx2audio.py presentation.pptx` + `python pptx2audio.py presentation.pptx en` """ import os import logging @@ -25,10 +25,11 @@ TOK_SLIDE_NOTE = {"it":"Note:", "en":"Note:"} def save_image_from_pptx(image:pptx.parts.image.Image, folder_path:str) -> None: - """Save an image to disk. + """Save an image to a folder. + Arguments: image: The image to save. - folder_path: the directory where we want save the image. + folder_path: The folder to save the image to. """ filename = f"{folder_path}/{image.filename}.{image.ext}" with open(filename, 'wb') as f: @@ -37,6 +38,7 @@ def save_image_from_pptx(image:pptx.parts.image.Image, folder_path:str) -> None: def __get_notes(note: slide.NotesSlide) -> str: print(note) return "" + def __extract_text_from_slide(slide_obj: slide.Slide, language:str="it") -> str: text_slide, text_note = "", "" @@ -52,11 +54,14 @@ def __extract_text_from_slide(slide_obj: slide.Slide, def extract_pptx_text(path_pptx:str, language:str="it") -> str: - """Extract the text from each slide and concat. + """Combine the text from each slide. + Arguments: - path_pptx (str): pptx presentation path + path_pptx (str): The PowerPoint presentation's file path. + language: The language of the presentation's content. + Returns: - str: all text generated by presentation + text_out: The presentation's text content. """ text_out:str = "" p: presentation.Presentation = pptx.Presentation(path_pptx) @@ -69,7 +74,6 @@ def extract_pptx_text(path_pptx:str, return text_out def main(): - """main function""" input_file_path, out_file_path, language = input_tool.get_sys_input(os.path.dirname(__file__)) m4b.init(BACK_END_TTS) text=extract_pptx_text(input_file_path) diff --git a/requirements.txt b/requirements.txt index 6cbb298..2b13f98 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ tinytag pypdf PyMuPDF fonttools +mkdocs-material diff --git a/txt2audio.py b/txt2audio.py index a58765f..c6b8b79 100644 --- a/txt2audio.py +++ b/txt2audio.py @@ -1,11 +1,11 @@ #!/usr/bin/python3 """ -file: [txt2audio.py](https://github.com/deangelisdf/write2audiobook/blob/main/txt2audio.py) +[`txt2audio.py`](https://github.com/deangelisdf/write2audiobook/blob/main/txt2audio.py) -description: Convert your txt (UTF-8) to audiobook in MP3 format. +Convert a `.txt` file to an MP3 file. Usage example: - `python txt2audio.py document.txt` + `python txt2audio.py document.txt en` """ import sys @@ -23,7 +23,6 @@ LANGUAGE = "it" def main(): - """main function""" _, output_file_path, language = input_tool.get_sys_input(os.path.dirname(__file__), format_output="mp3") text:str = ""