diff --git a/application/static/datasource.html b/application/static/datasource.html index 123b48d..7d63b4b 100644 --- a/application/static/datasource.html +++ b/application/static/datasource.html @@ -7,32 +7,31 @@ To build a data source, firstly purchase a matching audible & kindle book (typic

Audible to audio

To convert an audible audio book to an audio file (.mp3) I use AaxAudioConverter. Here are the steps to install and use:

    -
  1. Download the Windows Audible app from the Microsoft store
  2. +
  3. Download and install the Windows Audible app from the Microsoft store
  4. Open the audible app and download the audiobook you wish to convert
  5. Download AaxAudioConverter
  6. Run the application and click "Add" in the top left +
  7. Select the audiobook you downloaded in the audible app
  8. Select "MP3" as the export format and "Single file per AAX file". Then click convert +

Kindle to text

-

To convert a kindle book to text file (.txt) I developed an extension found in the dataset folder of this project. Here are the steps to install and use:

+

To convert a kindle book to text file (.txt):

    -
  1. Go to chrome://extensions/ in chrome
  2. -
  3. Click on "Load unpacked" in the top left and select the "extension" folder in the dataset directory - -
  4. -
  5. Open the first page of the book you want to scrape in the amazon cloud reader
  6. -
  7. Open the extension & click "Scrape book". Wait for the reader to scan through all the pages - -
  8. -
  9. When the scanner has reached the last page, press "Export book". This will download the text fill needed for step 1 - +
  10. Download and install Kindle App version 1.17 (NOTE: It must be this version or earlier to work)
  11. +
  12. Open the kindle app and download the book you wish to convert
  13. +
  14. Go to "Documents\My Kindle Content" and find your kindle book (.azw file) +
    +
  15. +
  16. Upload this file to Convert to a txt
+

If this doesn't work you can also follow the DeDRM guide

{% endblock %} diff --git a/application/static/images/kindle_step3.PNG b/application/static/images/kindle_step3.PNG new file mode 100644 index 0000000..fc09fb6 Binary files /dev/null and b/application/static/images/kindle_step3.PNG differ diff --git a/application/static/images/step2.PNG b/application/static/images/step2.PNG deleted file mode 100644 index bb68848..0000000 Binary files a/application/static/images/step2.PNG and /dev/null differ diff --git a/application/static/images/step4.PNG b/application/static/images/step4.PNG deleted file mode 100644 index 7f1321f..0000000 Binary files a/application/static/images/step4.PNG and /dev/null differ diff --git a/application/static/images/step5.PNG b/application/static/images/step5.PNG deleted file mode 100644 index 0fd8b99..0000000 Binary files a/application/static/images/step5.PNG and /dev/null differ diff --git a/dataset/extension/main.js b/dataset/extension/main.js deleted file mode 100644 index 3b783e9..0000000 --- a/dataset/extension/main.js +++ /dev/null @@ -1,104 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - var convert = document.getElementById('scrapeBook'); - var download = document.getElementById('exportBook'); - - convert.addEventListener('click', function() { - function getBook(){ - function scrapePage(){ - function hashString(str){ - let hash = 0; - for (let i = 0; i < str.length; i++) { - hash += Math.pow(str.charCodeAt(i) * 31, str.length - i); - hash = hash & hash; // Convert to 32bit integer - } - return hash; - } - - var hashes = {}; - var content = []; - function addDiv(div){ - let hash = hashString(div.innerText); - if (hashes[hash] === undefined) { - hashes[hash] = true; - content.push(div.outerHTML); - } - } - - var appFrame = document.querySelector('#KindleReaderIFrame').contentDocument; - var contentFrames = Array.from(appFrame.querySelectorAll('iframe')).map(f => f.contentDocument); - Array.from(contentFrames[1].querySelectorAll('body > div')).forEach(addDiv); - appFrame.getElementById('kindleReader_pageTurnAreaRight').click(); - return content; - } - - function extractContent(s) { - var span = document.createElement('span'); - span.innerHTML = s; - return span.textContent || span.innerText; - } - - function getFooter(){ - var appFrame = document.querySelector('#KindleReaderIFrame').contentDocument; - return appFrame.getElementById("kindleReader_footer_message").innerHTML.split(" "); - } - - function getCurrentPageNumber(){ - var footer = getFooter(); - return parseInt(footer[3]); - } - - var footer = getFooter(); - var num_pages = parseInt(footer[5]); - var current_page = parseInt(footer[3]); - var book = ""; - var last_page = ""; - - function getPageText(){ - text = "\n\n"; - page = scrapePage(); - for (let i = 0; i < page.length; i++){ - text += extractContent(page[i]) + "\n"; - } - if(text != last_page){ - book += text; - last_page = text; - } - current_page = getCurrentPageNumber(); - if(current_page == num_pages){ - alert("Extracted "+num_pages+" pages"); - var data = document.getElementById("data"); - if(data){ - data.innerHTML = book; - } else { - document.body.innerHTML += ""+book+""; - } - return; - } - setTimeout(getPageText, 1000); - } - - getPageText(); - return text; - } - - chrome.tabs.executeScript({ - code: '(' + getBook + ')();' - }, (result) => { - console.log(result); - }); - }, false); - - download.addEventListener('click', function() { - chrome.tabs.executeScript({ - code: '(function getData(){ return document.getElementById("data").innerHTML; })();' - }, (result) => { - console.log(result); - var blob = new Blob([result], {type: "text/plain"}); - var url = URL.createObjectURL(blob); - chrome.downloads.download({ - url: url, - filename: "book.txt" - }); - }); - }, false); -}, false); diff --git a/dataset/extension/manifest.json b/dataset/extension/manifest.json deleted file mode 100644 index ee26cf6..0000000 --- a/dataset/extension/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "manifest_version": 2, - "name": "Kindle webscraper", - "description": "This extension scrapes kindle books for the purpose of voice cloning", - "version": "1.0", - "browser_action": { - "default_popup": "popup.html" - }, - "permissions": ["downloads", "https://read.amazon.co.uk/*", "https://read.amazon.com/*", "cookies"] -} diff --git a/dataset/extension/popup.html b/dataset/extension/popup.html deleted file mode 100644 index b3c93a6..0000000 --- a/dataset/extension/popup.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - -

Kindle Converter

- - - - diff --git a/dataset/extension/style.css b/dataset/extension/style.css deleted file mode 100644 index 38050a3..0000000 --- a/dataset/extension/style.css +++ /dev/null @@ -1,15 +0,0 @@ -h1 { - font-family:Arial; - font-size:16px; -} -button { - background-color:#44c767; - border:1px solid #18ab29; - color:#ffffff; - font-family:Arial; - font-size:16px; - font-weight:bold; -} -button:hover { - background-color:#5cbf2a; -} diff --git a/synthesis/synthesis.md b/synthesis/synthesis.md index d69d856..3363df0 100644 --- a/synthesis/synthesis.md +++ b/synthesis/synthesis.md @@ -3,10 +3,16 @@ With trained model weights we can now implement the TTS app for our generated vo ## Arguments - **model_path**: The path to your generated model -- **waveglow_model_path**: The path to your waveglow model ([default found here](https://drive.google.com/file/d/1rpK8CzAAirq9sWZhe9nlfvxMF1dRgFbF/view)) +- **vocoder_type**: The vocoder type, `waveglow` or `hifigan` +- **vocoder_model_path**: The path to your vocoder model ([default waveglow model found here](https://drive.google.com/file/d/1rpK8CzAAirq9sWZhe9nlfvxMF1dRgFbF/view) [default hifigan model found here](https://drive.google.com/file/d/1qpgI41wNXFcH-iKq1Y42JlBC9j0je8PW/view?usp=sharing)) +- **hifigan_config_path**: The path to your hifigan config ([default higigan config found here](https://drive.google.com/file/d/1pAB2kQunkDuv6W5fcJiQ0CY8xcJKB22e/view?usp=sharing)) - **text**: Text you wish to synthesize - **graph_output_path (optional)**: Path to save alignment graph to - **audio_output_path (optional)**: Path to save generated audio to ## How to run -`python synthesize.py -m checkpoint_500000 -w waveglow_256channels_universal_v5.pt -t "Hello everyone, how are you?" -g graph.png -a audio.wav` +### Using vocoder waveglow +`python synthesize.py -vt waveglow -m checkpoint_500000 -vm waveglow_256channels_universal_v5.pt -t "Hello everyone, how are you?" -g graph.png -a audio.wav` + +### Using vocoder hifigan +`python synthesize.py -vt hifigan -m checkpoint_500000 -vm g_02500000 -hc config.json -t "Hello everyone, how are you?" -g graph.png -a audio.wav` diff --git a/synthesis/synthesize.py b/synthesis/synthesize.py index de3b305..7d443bc 100644 --- a/synthesis/synthesize.py +++ b/synthesis/synthesize.py @@ -2,10 +2,8 @@ import argparse import os import inflect import matplotlib.pyplot as plt -from training.tacotron2_model import Tacotron2 import torch import numpy as np -import glow # noqa import matplotlib from os.path import dirname, abspath import sys @@ -13,9 +11,11 @@ import sys sys.path.append(dirname(dirname(abspath(__file__)))) matplotlib.use("Agg") +import glow # noqa +from training.tacotron2_model import Tacotron2 from training.clean_text import clean_text from synthesis.waveglow import load_waveglow_model, generate_audio_waveglow -from synthesis.hifigan import generate_audio_hifigan +from synthesis.hifigan import load_hifigan_model, generate_audio_hifigan def load_model(model_path): @@ -123,19 +123,28 @@ if __name__ == "__main__": """Synthesize audio using model and vocoder""" parser = argparse.ArgumentParser(description="Synthesize audio using model and vocoder") parser.add_argument("-m", "--model_path", type=str, help="tacotron2 model path", required=True) - parser.add_argument("-w", "--waveglow_model_path", type=str, help="waveglow model path", required=True) + parser.add_argument("-vt", "--vocoder_type", type=str, help="vocoder type(waveglow or hifigan)", required=True) + parser.add_argument("-vm", "--vocoder_model_path", type=str, help="vocoder model path", required=True) + parser.add_argument("-hc", "--hifigan_config_path", type=str, help="hifigan_config path", required=False) parser.add_argument("-t", "--text", type=str, help="text to synthesize", required=True) parser.add_argument("-g", "--graph_output_path", type=str, help="path to save alignment graph to", required=False) parser.add_argument("-a", "--audio_output_path", type=str, help="path to save output audio to", required=False) args = parser.parse_args() assert os.path.isfile(args.model_path), "Model not found" - assert os.path.isfile(args.waveglow_model_path), "Waveglow model not found" + assert os.path.isfile(args.vocoder_model_path), "vocoder model not found" model = load_model(args.model_path) - waveglow_model = load_waveglow_model(args.waveglow_path) + vocoder_type = args.vocoder_type + vocoder_model = None + if vocoder_type == "hifigan": + assert os.path.isfile(args.hifigan_config_path), "hifigan config not found" + vocoder_model = load_hifigan_model(args.vocoder_model_path, args.hifigan_config_path) + elif vocoder_type == "waveglow": + vocoder_model = load_waveglow_model(args.vocoder_model_path) + inflect_engine = inflect.engine() synthesize( - model, args.text, inflect_engine, args.graph_output_path, args.audio_output_path, waveglow_model, "waveglow" + model, args.text, inflect_engine, args.graph_output_path, args.audio_output_path, vocoder_model, vocoder_type )