Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support: txt file support added #16

Merged
merged 2 commits into from
Oct 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 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 @@ -71,15 +71,18 @@ sudo apt update && sudo apt install espeak ffmpeg libespeak1

## Project status

## V1.0.0
This project is currently in development. Any contributions are welcome.

## Changelog

**V2.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
- [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