From 0532573053e2885fc2888f441e02316d60c8114e Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 14:39:28 +0530 Subject: [PATCH 1/8] :hammer: Refactoring code --- Pipfile | 13 ------------- Pipfile.lock | 36 ------------------------------------ audiobook/__init__.py | 29 +---------------------------- audiobook/main.py | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 77 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock mode change 100755 => 100644 audiobook/__init__.py create mode 100644 audiobook/main.py diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 895fb71..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -pyttsx3 = "*" -pypdf2 = "*" - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 70b95a4..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,36 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "09a8d59cb5b927c5885f7d9e36133ba9c41cb62ed02ab5d8357468b0e0c08beb" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "pypdf2": { - "hashes": [ - "sha256:7c18c1d48e56547b1c33f772dc15d6adbd1f4020b62e64bb4a0bc0ee2ab94511", - "sha256:9c81fc06be50fbf2e6199e8c2eac05f3eaafae4b3905ecca41200f5b02ac43d7" - ], - "index": "pypi", - "version": "==1.27.5" - }, - "pyttsx3": { - "hashes": [ - "sha256:a585b6d8cffc19bd92db1e0ccbd8aa9c6528dd2baa5a47045d6fed542a44aa19" - ], - "index": "pypi", - "version": "==2.90" - } - }, - "develop": {} -} diff --git a/audiobook/__init__.py b/audiobook/__init__.py old mode 100755 new mode 100644 index 9fbe641..86c95fc --- a/audiobook/__init__.py +++ b/audiobook/__init__.py @@ -1,28 +1 @@ -#!/usr/bin/python - -import pyttsx3 -import PyPDF2 - - -class AudioBook: - def __init__(self, book_path): - self.book_path = book_path - - def text_to_speech(self): - with open(self.book_path, "rb") as book: - pdfReader = PyPDF2.PdfFileReader(book) - pages = pdfReader.numPages - print("The Book has total: " + str(pages) + " pages!") - - # initiatiazing the pyttsx3 and setting voice speed to 125 - engine = pyttsx3.init() - engine.setProperty("rate", 125) - - start_page = int(input("Please enter the page number: ")) - for num in range(start_page, pages): - print("Reading page number " + str(num) + " page!") - page = pdfReader.getPage(num) - text = page.extractText() - engine.say(text) - engine.runAndWait() - engine.stop() +from audiobook.main import AudioBook \ No newline at end of file diff --git a/audiobook/main.py b/audiobook/main.py new file mode 100644 index 0000000..d1b5ca2 --- /dev/null +++ b/audiobook/main.py @@ -0,0 +1,36 @@ +import pyttsx3 +import PyPDF2 + +speed_dict = { + "slow": 100, + "normal": 150, + "fast": 200} + +def speak_text(engine, text): + engine.say(text) + engine.runAndWait() + + +class AudioBook: + def __init__(self, speaker=None, speed="medium"): + self.speaker = speaker + self.engine = pyttsx3.init() + self.engine.setProperty("rate", speed_dict[speed]) + + def read_book(self, book_path): + with open(book_path, "rb") as fp: + pdfReader = PyPDF2.PdfFileReader(fp) + pages = pdfReader.numPages + speak_text(self.engine, "The Book has total: " + str(pages) + " pages!") + speak_text(self.engine, "Please enter the page number: ") + + start_page = int(input("Please enter the page number: ")) + speak_text(self.engine, "Reading the book now!") + + for num in range(start_page, pages): + speak_text(self.engine, "Reading page number " + str(num)) + page = pdfReader.getPage(num) + text = page.extractText() + speak_text(self.engine, text) + + From e3dc0dc0bd9f7a2be8da7969e9a040fe33cadc76 Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 15:02:07 +0530 Subject: [PATCH 2/8] :hammer: flake8 lint --- audiobook/main.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/audiobook/main.py b/audiobook/main.py index d1b5ca2..a625c12 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -6,10 +6,11 @@ "normal": 150, "fast": 200} + def speak_text(engine, text): engine.say(text) engine.runAndWait() - + class AudioBook: def __init__(self, speaker=None, speed="medium"): @@ -21,16 +22,14 @@ def read_book(self, book_path): with open(book_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) pages = pdfReader.numPages - speak_text(self.engine, "The Book has total: " + str(pages) + " pages!") + speak_text(self.engine, f"The book has total {str(pages)} pages!") speak_text(self.engine, "Please enter the page number: ") - + start_page = int(input("Please enter the page number: ")) speak_text(self.engine, "Reading the book now!") - + for num in range(start_page, pages): speak_text(self.engine, "Reading page number " + str(num)) page = pdfReader.getPage(num) text = page.extractText() speak_text(self.engine, text) - - From 08dc33106e4f5a4830fa1c9c596ec9a779c8827d Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 17:03:39 +0530 Subject: [PATCH 3/8] adding book navigation --- audiobook/__init__.py | 2 +- audiobook/main.py | 77 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/audiobook/__init__.py b/audiobook/__init__.py index 86c95fc..b2a3a40 100644 --- a/audiobook/__init__.py +++ b/audiobook/__init__.py @@ -1 +1 @@ -from audiobook.main import AudioBook \ No newline at end of file +from audiobook.main import AudioBook diff --git a/audiobook/main.py b/audiobook/main.py index a625c12..3283c96 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -1,35 +1,82 @@ import pyttsx3 import PyPDF2 +import os +import sys +import json +import time +import keyboard +import logging + +logger = logging.getLogger("PyPDF2") +logger.setLevel(logging.INFO) speed_dict = { "slow": 100, "normal": 150, - "fast": 200} - + "fast": 200} def speak_text(engine, text): engine.say(text) engine.runAndWait() - class AudioBook: - def __init__(self, speaker=None, speed="medium"): - self.speaker = speaker + def __init__(self, speed="normal"): self.engine = pyttsx3.init() self.engine.setProperty("rate", speed_dict[speed]) - - def read_book(self, book_path): - with open(book_path, "rb") as fp: + + def create_json_book(self, pdf_file_path): + book_dict = {} + with open(pdf_file_path, "rb") as fp: + pdfReader = PyPDF2.PdfFileReader(fp) + pages = pdfReader.numPages + for num in range(0, pages): + pageObj = pdfReader.getPage(num) + text = pageObj.extractText() + book_dict[num] = text + return book_dict, pages + + def read_book(self, pdf_file_path): + with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) pages = pdfReader.numPages + speak_text(self.engine, f"The book has total {str(pages)} pages!") speak_text(self.engine, "Please enter the page number: ") + start_page = int(input("Please enter the page number: ")) - 1 + reading = True + while reading: + if start_page > pages or start_page < 0: + speak_text(self.engine, "Invalid page number!") + speak_text(self.engine, f"The book has total {str(pages)} pages!") + start_page = int(input("Please enter the page number: ")) + + speak_text(self.engine, f"Reading page {str(start_page+1)}") + pageObj = pdfReader.getPage(start_page) + pageText = pageObj.extractText() + speak_text(self.engine, pageText) + + user_input = input("Please Select an option: \n 1. Type 'r' to read again: \n 2. Type 'p' to read previous page\n 3. Type 'n' to read next page\n 4. Type 'q' to quit:\n 5. Type page number to read that page:\n") + if user_input == "r": + speak_text(self.engine, f"Reading page {str(start_page+1)}") + continue + elif user_input == "p": + speak_text(self.engine, "Reading previous page") + start_page -= 1 + continue + elif user_input == "n": + speak_text(self.engine, "Reading next page") + start_page += 1 + continue + elif user_input == "q": + speak_text(self.engine, "Quitting the book!") + break + elif user_input.isnumeric(): + start_page = int(user_input) - 1 + else: + user_input = input("Please Select an option: \n 1. Type 'r' to read again: \n 2. Type 'p' to read previous page\n 3. Type 'n' to read next page\n 4. Type 'q' to quit:\n 5. Type page number to read that page:\n") + continue + + - start_page = int(input("Please enter the page number: ")) - speak_text(self.engine, "Reading the book now!") - for num in range(start_page, pages): - speak_text(self.engine, "Reading page number " + str(num)) - page = pdfReader.getPage(num) - text = page.extractText() - speak_text(self.engine, text) + \ No newline at end of file From fb191fb5696562264ba6396fac9a86501daadf74 Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 17:51:41 +0530 Subject: [PATCH 4/8] fixing flake8 --- audiobook/main.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/audiobook/main.py b/audiobook/main.py index 3283c96..5997197 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -1,29 +1,27 @@ import pyttsx3 import PyPDF2 -import os -import sys -import json -import time -import keyboard import logging logger = logging.getLogger("PyPDF2") logger.setLevel(logging.INFO) + speed_dict = { "slow": 100, "normal": 150, - "fast": 200} + "fast": 200} + def speak_text(engine, text): engine.say(text) engine.runAndWait() + class AudioBook: def __init__(self, speed="normal"): self.engine = pyttsx3.init() self.engine.setProperty("rate", speed_dict[speed]) - + def create_json_book(self, pdf_file_path): book_dict = {} with open(pdf_file_path, "rb") as fp: @@ -34,12 +32,12 @@ def create_json_book(self, pdf_file_path): text = pageObj.extractText() book_dict[num] = text return book_dict, pages - + def read_book(self, pdf_file_path): with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) pages = pdfReader.numPages - + speak_text(self.engine, f"The book has total {str(pages)} pages!") speak_text(self.engine, "Please enter the page number: ") start_page = int(input("Please enter the page number: ")) - 1 @@ -49,12 +47,12 @@ def read_book(self, pdf_file_path): speak_text(self.engine, "Invalid page number!") speak_text(self.engine, f"The book has total {str(pages)} pages!") start_page = int(input("Please enter the page number: ")) - + speak_text(self.engine, f"Reading page {str(start_page+1)}") pageObj = pdfReader.getPage(start_page) pageText = pageObj.extractText() speak_text(self.engine, pageText) - + user_input = input("Please Select an option: \n 1. Type 'r' to read again: \n 2. Type 'p' to read previous page\n 3. Type 'n' to read next page\n 4. Type 'q' to quit:\n 5. Type page number to read that page:\n") if user_input == "r": speak_text(self.engine, f"Reading page {str(start_page+1)}") @@ -75,8 +73,3 @@ def read_book(self, pdf_file_path): else: user_input = input("Please Select an option: \n 1. Type 'r' to read again: \n 2. Type 'p' to read previous page\n 3. Type 'n' to read next page\n 4. Type 'q' to quit:\n 5. Type page number to read that page:\n") continue - - - - - \ No newline at end of file From 211edb843c0a1630cd42279b7a5220b5d7ef22a3 Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 22:16:04 +0530 Subject: [PATCH 5/8] feature: password file can open --- audiobook/main.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/audiobook/main.py b/audiobook/main.py index 5997197..42a0f70 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -1,3 +1,4 @@ +import os import pyttsx3 import PyPDF2 import logging @@ -22,18 +23,33 @@ def __init__(self, speed="normal"): self.engine = pyttsx3.init() self.engine.setProperty("rate", speed_dict[speed]) - def create_json_book(self, pdf_file_path): + def create_json_book(self, pdf_file_path, password=None): + + if not os.path.exists(pdf_file_path): + raise FileNotFoundError("File not found!") + + if not pdf_file_path.endswith(".pdf"): + raise ValueError("File must be a pdf!") + book_dict = {} with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) + if pdfReader.isEncrypted: + pdfReader.decrypt(password) pages = pdfReader.numPages for num in range(0, pages): pageObj = pdfReader.getPage(num) text = pageObj.extractText() book_dict[num] = text return book_dict, pages - + def read_book(self, pdf_file_path): + if not os.path.exists(pdf_file_path): + raise FileNotFoundError("File not found!") + + if not pdf_file_path.endswith(".pdf"): + raise ValueError("File must be a pdf!") + with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) pages = pdfReader.numPages From c0e01e48a9a80671bafc624077db04fa5b8e841c Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Thu, 13 Oct 2022 22:50:26 +0530 Subject: [PATCH 6/8] support: for password file --- audiobook/main.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/audiobook/main.py b/audiobook/main.py index 42a0f70..1f3583e 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -22,7 +22,7 @@ class AudioBook: def __init__(self, speed="normal"): self.engine = pyttsx3.init() self.engine.setProperty("rate", speed_dict[speed]) - + def create_json_book(self, pdf_file_path, password=None): if not os.path.exists(pdf_file_path): @@ -35,6 +35,7 @@ def create_json_book(self, pdf_file_path, password=None): with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) if pdfReader.isEncrypted: + logging.info("File is encrypted, trying to decrypt...") pdfReader.decrypt(password) pages = pdfReader.numPages for num in range(0, pages): @@ -43,7 +44,7 @@ def create_json_book(self, pdf_file_path, password=None): book_dict[num] = text return book_dict, pages - def read_book(self, pdf_file_path): + def read_book(self, pdf_file_path, password=None): if not os.path.exists(pdf_file_path): raise FileNotFoundError("File not found!") @@ -52,8 +53,10 @@ def read_book(self, pdf_file_path): with open(pdf_file_path, "rb") as fp: pdfReader = PyPDF2.PdfFileReader(fp) + if pdfReader.isEncrypted: + logging.info("File is encrypted, trying to decrypt...") + pdfReader.decrypt(password) pages = pdfReader.numPages - speak_text(self.engine, f"The book has total {str(pages)} pages!") speak_text(self.engine, "Please enter the page number: ") start_page = int(input("Please enter the page number: ")) - 1 From a09f3c44e4fec4612c545568c2f5603b48a22f94 Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:49:32 +0530 Subject: [PATCH 7/8] feature: audiobook can be saved locally --- audiobook/main.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/audiobook/main.py b/audiobook/main.py index 1f3583e..f8165af 100644 --- a/audiobook/main.py +++ b/audiobook/main.py @@ -6,14 +6,15 @@ logger = logging.getLogger("PyPDF2") logger.setLevel(logging.INFO) - speed_dict = { "slow": 100, "normal": 150, "fast": 200} -def speak_text(engine, text): +def speak_text(engine, text, print=False): + if print: + print(text) engine.say(text) engine.runAndWait() @@ -43,7 +44,29 @@ def create_json_book(self, pdf_file_path, password=None): text = pageObj.extractText() book_dict[num] = text return book_dict, pages + + def save_audio(self, pdf_file_path, password=None): + if not os.path.exists(pdf_file_path): + raise FileNotFoundError("File not found!") + + if not pdf_file_path.endswith(".pdf"): + raise ValueError("File must be a pdf!") + with open(pdf_file_path, "rb") as fp: + basename = os.path.basename(pdf_file_path).split(".")[0] + os.makedirs(basename, exist_ok=True) + logging.info('Saving audio files in folder: {}'.format(basename)) + pdfReader = PyPDF2.PdfFileReader(fp) + if pdfReader.isEncrypted: + logging.info("File is encrypted, trying to decrypt...") + pdfReader.decrypt(password) + pages = pdfReader.numPages + for num in range(0, pages): + pageObj = pdfReader.getPage(num) + text = pageObj.extractText() + self.engine.save_to_file(text, os.path.join(basename, basename + "_" + (str(num) + ".mp3"))) + self.engine.runAndWait() + def read_book(self, pdf_file_path, password=None): if not os.path.exists(pdf_file_path): raise FileNotFoundError("File not found!") From f010fe06ffddfff5847425df9c37ecea3ac2909d Mon Sep 17 00:00:00 2001 From: Deepak Raj <54245038+codePerfectPlus@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:57:24 +0530 Subject: [PATCH 8/8] Updating README for changes --- README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4dc47d1..e85a798 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,10 @@ pip install audiobook ```python from audiobook import AudioBook -ab = AudioBook("file_path") -ab.text_to_speech() +ab = AudioBook() # argument: Speech-Speed="slow/normal/fast" + +ab.save_audio(file_path, password=None) # save audio file +ab.read_book(file_path, password=None) # listen to the book ``` ## Usages @@ -69,7 +71,18 @@ sudo apt update && sudo apt install espeak ffmpeg libespeak1 ## Project status -- Alpha +## V1.0.0 + +- [x] Save Audio Book locally +- [x] Listen to the book +- [x] Speech-speed control +- [x] Read password protected PDF +- [x] Create json file for the book + +## Upcoming Features + +- [ ] Support more extensions + ## Author