Skip to content

Commit

Permalink
Merge pull request #16 from codePerfectPlus/patch-1
Browse files Browse the repository at this point in the history
Support: txt file support added
  • Loading branch information
DrakeEntity committed Oct 15, 2022
2 parents 11950a1 + 48ca738 commit d242d09
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 83 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pip install audiobook

```python
from audiobook import AudioBook
ab = AudioBook() # argument: Speech-Speed="slow/normal/fast"
ab = AudioBook(speed="normal") # 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
Expand Down Expand Up @@ -79,10 +79,9 @@ This project is currently in development. Any contributions are welcome.
- [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
- [x] Read password-protected PDF
- [x] Create JSON file for the book
- [ ] Change the voice of the narrator

- [ ] Support more extensions

Expand Down
182 changes: 105 additions & 77 deletions audiobook/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,55 @@
logger = logging.getLogger("PyPDF2")
logger.setLevel(logging.INFO)

supported_file_types = (".pdf", ".txt")

speed_dict = {
"slow": 100,
"normal": 150,
"fast": 200}


def speak_text(engine, text, print=False):
if print:
def speak_text(engine, text, display=True):
if display:
print(text)
engine.say(text)
engine.runAndWait()


class AudioBook:
"""
AudioBook class
methods:
file_check: checks if file exists
pdf_to_json: converts pdf to json format
create_json_book: Creates json book from input file by calling respective method
save_audio: saves audio files in folder
read_book: reads the book
sample usage:
ab = AudioBook(speed="normal")
ab.read_book(file_path, password="abcd")
"""

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):

def file_check(self, file_path):
"""
checks file format and if file exists
"""
if not os.path.exists(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:

if not file_path.endswith(supported_file_types):
raise ValueError("File format not supported!")

def pdf_to_json(self, input_file_path, password=None):
""" sub method to create json book from pdf file"""
json_book = {}
with open(input_file_path, "rb") as fp:
pdfReader = PyPDF2.PdfFileReader(fp)
if pdfReader.isEncrypted:
logging.info("File is encrypted, trying to decrypt...")
Expand All @@ -42,76 +63,83 @@ def create_json_book(self, pdf_file_path, password=None):
for num in range(0, pages):
pageObj = pdfReader.getPage(num)
text = pageObj.extractText()
book_dict[num] = text
return book_dict, pages
json_book[num] = text
return json_book, pages

def save_audio(self, pdf_file_path, password=None):
if not os.path.exists(pdf_file_path):
raise FileNotFoundError("File not found!")
def txt_to_json(self, input_file_path):
""" sub method to create json book from txt file """
json_book = {}
with open(input_file_path, "r") as fp:
file_data = fp.read()

if not pdf_file_path.endswith(".pdf"):
raise ValueError("File must be a pdf!")
# split text into pages of 2000 characters
for i in range(0, len(file_data), 2000):
json_book[i] = file_data[i:i+2000]
return json_book, len(json_book)

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!")
def create_json_book(self, input_file_path, password=None):
""" method to create json book from input file
it calls respective method based on file format """
self.file_check(input_file_path)
if input_file_path.endswith(".pdf"):
json_book, pages = self.pdf_to_json(input_file_path, password)
elif input_file_path.endswith(".txt"):
json_book, pages = self.txt_to_json(input_file_path)
return json_book, pages


def save_audio(self, input_file_path, password=None):
""" method to save audio files in folder """
self.file_check(input_file_path)
logging.info("Creating your audiobook... Please wait...")
json_book, pages = self.create_json_book(input_file_path, password)

if not pdf_file_path.endswith(".pdf"):
raise ValueError("File must be a pdf!")
book_name = os.path.basename(input_file_path).split(".")[0]
os.makedirs(book_name, exist_ok=True)
logging.info('Saving audio files in folder: {}'.format(book_name))

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
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: "))
for page_num, text in json_book.items():
self.engine.save_to_file(text, os.path.join(book_name, book_name + "_page_" + (str(page_num+1) + ".mp3")))
self.engine.runAndWait()


def read_book(self, input_file_path, password=None):
""" method to read the book """
self.file_check(input_file_path)
logging.info("Creating your audiobook... Please wait...")
json_book, pages = self.create_json_book(input_file_path, password)
speak_text(self.engine, f"The book has total {str(pages)} pages!")
speak_text(self.engine, "Please enter the page number: ", display=False)
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)
speak_text(self.engine, f"Reading page {str(start_page+1)}")
pageText = json_book[start_page]
speak_text(self.engine, pageText, display=False)

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")
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
continue
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="audiobook",
version="1.0.4",
version="2.0.0",
author="CodePerfectPlus",
author_email="deepak008@live.com",
description="Listen to your favourite audiobook",
Expand Down

0 comments on commit d242d09

Please sign in to comment.