From ff4b9d9e997e8cb754e37b521cc475df62ebc5a7 Mon Sep 17 00:00:00 2001
From: erew123 <35898566+erew123@users.noreply.github.com>
Date: Mon, 8 Jan 2024 00:56:36 +0000
Subject: [PATCH] Updates to reduce browser load
Pagination of files list.
No Playback option
Better clearing of played back audio from memory
---
.../tts_chunk_player/tts_chunk_player.html | 413 +++++++++++++++---
1 file changed, 345 insertions(+), 68 deletions(-)
diff --git a/templates/tts_chunk_player/tts_chunk_player.html b/templates/tts_chunk_player/tts_chunk_player.html
index 21d3c6d..41082dc 100644
--- a/templates/tts_chunk_player/tts_chunk_player.html
+++ b/templates/tts_chunk_player/tts_chunk_player.html
@@ -175,27 +175,32 @@
}
.progress-overlay {
- position: absolute;
- top: 10px;
- right: 10px;
- background: rgba(255, 255, 255, 0.9);
- border-radius: 5px;
- padding: 10px;
- display: flex;
- flex-direction: column; /* Stack items vertically */
- align-items: center; /* Center items horizontally within the container */
- justify-content: center; /* Center items vertically within the container */
- z-index: 10;
-}
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ background: rgba(255, 255, 255, 0.9);
+ border-radius: 5px;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ /* Stack items vertically */
+ align-items: center;
+ /* Center items horizontally within the container */
+ justify-content: center;
+ /* Center items vertically within the container */
+ z-index: 10;
+ }
-/* Ensure the text is wrapped in a container with a class, e.g., .progress-text */
-.progress-text {
- text-align: right; /* Center the text horizontally */
- margin-top: 10px; /* Add space between the spinner and the text */
-}
+ /* Ensure the text is wrapped in a container with a class, e.g., .progress-text */
+ .progress-text {
+ text-align: right;
+ /* Center the text horizontally */
+ margin-top: 10px;
+ /* Add space between the spinner and the text */
+ }
-#progressIndicator {
+ #progressIndicator {
/* Adjust this if you want to position the spinning disk differently */
display: inline-block;
margin-left: 20px;
@@ -413,6 +418,78 @@
margin-left: 45px;
/* Adjust the value as needed */
}
+
+ /* Pagination Buttons Styling */
+ .pagination-btn {
+ padding: 5px 10px;
+ /* Adjust padding to reduce height */
+ font-size: 0.8em;
+ /* Adjust font size for smaller buttons */
+ line-height: 1;
+ /* Adjust line height to match the smaller size */
+ margin: 2px;
+ /* Optional: adjust spacing between buttons */
+ }
+
+ /* Smaller input field for jump-to-page */
+ .pagination-input {
+ height: 20px;
+ /* Adjust height for smaller input field */
+ padding: 2px 5px;
+ /* Adjust padding for smaller input field */
+ font-size: 0.8em;
+ /* Adjust font size for smaller input field */
+ line-height: 1;
+ /* Adjust line height to match the smaller size */
+ vertical-align: middle;
+ /* Align with buttons if necessary */
+ }
+
+ /* Apply the styles to your pagination controls */
+ #paginationControls button {
+ /* Apply the button styling */
+ height: auto;
+ /* Let padding control the height */
+ min-height: 20px;
+ /* Set a minimum height if needed */
+ }
+
+ #paginationControls input[type="number"] {
+ /* Apply the input styling */
+ }
+
+ /* Smaller input field for jump-to-page */
+ .pagination-input {
+ height: 2px;
+ /* Reduce the height */
+ padding: 0px 0px;
+ /* Reduce the padding to decrease overall height */
+ font-size: 0.8em;
+ /* Optionally reduce the font size */
+ margin-bottom: 13px;
+ margin-top: 2px;
+ border: 0px solid #ccc;
+ /* Adjust border styling if needed */
+ line-height: normal;
+ /* Adjust line height to match the new size */
+ vertical-align: top;
+ /* Align vertically with buttons */
+ }
+
+ /* Apply the styles to your pagination controls */
+ #paginationControls1 button {
+ /* Apply the button styling */
+ height: auto;
+ /* Let padding control the height */
+ min-height: 20px;
+ /* Set a minimum height if needed */
+ margin-top: 15px
+ }
+
+ #paginationControls1 input[type="number"] {
+ /* Apply the input styling */
+ margin-top: 15px
+ }
@@ -469,6 +546,7 @@
@@ -524,9 +602,23 @@
+
+
@@ -537,35 +629,35 @@
import Crunker from './crunker.esm.js';
async function exportMP3() {
- const crunker = new Crunker();
- const fileUrls = ttsList.map(item => item.fileUrl);
- const progressIndicator = document.getElementById('progressIndicator');
- const progressText = document.getElementById('progressText');
+ const crunker = new Crunker();
+ const fileUrls = ttsList.map(item => item.fileUrl);
+ const progressIndicator = document.getElementById('progressIndicator');
+ const progressText = document.getElementById('progressText');
- // Show progress indicator and update text
- if (progressIndicator && progressText) {
- progressText.textContent = 'Export';
- progressText.style.color = 'black'; // Set the text color to black
- progressIndicator.style.display = 'block';
- }
-
- try {
- const audioBuffers = await crunker.fetchAudio(...fileUrls);
- const combined = crunker.concatAudio(audioBuffers);
- const output = crunker.export(combined, "audio/wav");
- crunker.download(output.blob, "combined_audio"); // This will download the file as 'combined_audio.mp3'
- } catch (error) {
- console.error('Error combining files:', error);
- if (progressText) {
- progressText.textContent = 'Error during export!';
+ // Show progress indicator and update text
+ if (progressIndicator && progressText) {
+ progressText.textContent = 'Export';
+ progressText.style.color = 'black'; // Set the text color to black
+ progressIndicator.style.display = 'block';
}
- } finally {
- // Hide progress indicator after completion or error
- if (progressIndicator) {
- progressIndicator.style.display = 'none';
+
+ try {
+ const audioBuffers = await crunker.fetchAudio(...fileUrls);
+ const combined = crunker.concatAudio(audioBuffers);
+ const output = crunker.export(combined, "audio/wav");
+ crunker.download(output.blob, "combined_audio"); // This will download the file as 'combined_audio.mp3'
+ } catch (error) {
+ console.error('Error combining files:', error);
+ if (progressText) {
+ progressText.textContent = 'Error during export!';
+ }
+ } finally {
+ // Hide progress indicator after completion or error
+ if (progressIndicator) {
+ progressIndicator.style.display = 'none';
+ }
}
}
-}
// Attach exportMP3 to the window object to make it globally accessible
window.exportMP3 = exportMP3;
@@ -582,7 +674,7 @@
let audioQueue = [];
let currentlyPlayingIndex = 0;
let isPlaying = false;
- let playModeValue = 'local';
+ let playModeValue = localStorage.getItem('playMode') || 'local';
let currentSound = null;
let preloadThreshold = 2; // Number of files to preload before starting playback
let isStreamInitialized = false;
@@ -591,6 +683,9 @@
const howlInstances = {};
let listPlaying = false;
let listPlayIndex = 0;
+ let currentPage = 1;
+ let itemsPerPage = 100; // Adjust as needed
+
////////////////////////////////////
//////// Progress Indicator ////////
@@ -602,7 +697,7 @@
if (progressIndicator && generationProgress) {
let message = '';
- console.log("PlayType is:", playType);
+ //console.log("PlayType is:", playType);
if (playType === 'stream') {
// When streaming, display a different message
message = '      Streaming...';
@@ -650,6 +745,7 @@
const volume = parseFloat(document.getElementById("volume").value);
const chunkSize = parseInt(document.getElementById("chunkSize").value);
const playType = document.getElementById('playType').value; // Play type (chunk or stream)
+ playModeValue = document.getElementById('playMode').value;
let cleanedText = textInput.replace(/ \- | \– /g, ' ');
cleanedText = cleanedText.replace(/%/g, " percent");
@@ -685,9 +781,14 @@
if (stopTTSGeneration) break;
showProgress(i + 1, totalChunks, playType);
if (playModeValue === 'local') {
+ // Generate the chunk and play it locally
await generateAndCache(chunks[i], language, characterVoice, volume);
- } else {
+ } else if (playModeValue === 'remote') {
+ // Generate the chunk and play it remotely
await generateAndPlayRemote(chunks[i], language, characterVoice, volume);
+ } else if (playModeValue === 'none') {
+ // Generate the chunk but do not play it
+ await generateWithoutPlayback(chunks[i], language, characterVoice);
}
}
}
@@ -735,6 +836,7 @@
const result = await response.json();
if (result.output_file_url) {
+ //console.log('TTS Generation Result:', result);
// If an ID was passed in, we're regenerating an existing item
if (id !== null) {
let itemIndex = ttsList.findIndex(item => item.id === id);
@@ -748,6 +850,15 @@
// No ID was passed in, so we add a new item to the list
addToTTSList(result.output_file_url, chunk, characterVoice, language);
}
+ const newPage = Math.ceil(ttsList.length / itemsPerPage);
+ //console.log('New Page Calculated:', newPage);
+ if (currentPage !== newPage) {
+ currentPage = newPage; // Move to the new page where the item was added
+ //console.log('Updating Current Page to:', currentPage);
+ }
+
+ // Refresh the list display to reflect the new pagination state
+ updateUIList();
// Update the audio queue and UI
const sound = new Howl({
@@ -769,6 +880,56 @@
}
}
+ async function generateWithoutPlayback(chunk, language, characterVoice, id = null) {
+ // Perform the generation process as usual but do not play the audio
+ try {
+ const data = new URLSearchParams({
+ text_input: chunk.trim(),
+ text_filtering: "standard",
+ character_voice_gen: characterVoice,
+ narrator_enabled: "false",
+ narrator_voice_gen: characterVoice,
+ text_not_inside: "character",
+ language: language,
+ output_file_name: "TTS",
+ output_file_timestamp: "true",
+ autoplay: "false",
+ autoplay_volume: "0.1"
+ });
+ const response = await fetch("http://127.0.0.1:7851/api/tts-generate", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: data,
+ });
+ const result = await response.json();
+ if (result.output_file_url) {
+ // If an ID was passed in, we're regenerating an existing item
+ if (id !== null) {
+ let itemIndex = ttsList.findIndex(item => item.id === id);
+ if (itemIndex !== -1) {
+ ttsList[itemIndex].fileUrl = result.output_file_url;
+ // Other properties can be updated as needed, e.g., in case the language or voice has changed
+ ttsList[itemIndex].language = language;
+ ttsList[itemIndex].characterVoice = characterVoice;
+ }
+ } else {
+ // No ID was passed in, so we add a new item to the list
+ addToTTSList(result.output_file_url, chunk, characterVoice, language);
+ }
+ const newPage = Math.ceil(ttsList.length / itemsPerPage);
+ if (currentPage !== newPage) {
+ currentPage = newPage; // Move to the new page where the item was added
+ }
+ updateUIList();
+ }
+ } catch (error) {
+ console.error("Error in generateWithoutPlayback:", error);
+ }
+ }
+
+
function addToTTSList(fileUrl, text, characterVoice, language) {
try {
ttsList.push({
@@ -784,6 +945,7 @@
}
}
+
async function regenerateTTS(id) {
// Find the details of the TTS to regenerate
const ttsDetails = ttsList.find(item => item.id === id);
@@ -804,7 +966,13 @@
}
listDisplay.innerHTML = ''; // Clear the current list
- ttsList.forEach(item => {
+ // Determine the range of items to display for pagination
+ const start = (currentPage - 1) * itemsPerPage;
+ const end = start + itemsPerPage;
+ const paginatedItems = ttsList.slice(start, end);
+
+ // Add items to the display for the current page
+ paginatedItems.forEach(item => {
// Extract just the file name from the URL
const wavFileName = item.fileUrl.split('/').pop();
@@ -814,30 +982,36 @@
const entryDiv = document.createElement('div');
entryDiv.id = `item-${item.id}`; // Assign an ID to the div for highlighting
entryDiv.classList.add('ttsListItem'); // Add a class for styling
- entryDiv.id = `item-${item.id}`; // Make sure this is unique and correct
// Update the Play/Stop button's onclick to call a function that handles playing and highlighting
entryDiv.innerHTML = `
-
-
- ID: ${item.id}
- Voice: ${item.characterVoice}
- Language: ${item.language}
- Wav: ${wavFileName}
-
- ${displayText}
+
+
+ ID: ${item.id}
+ Voice: ${item.characterVoice}
+ Language: ${item.language}
+ Wav: ${wavFileName}
+
+ ${displayText}
`;
listDisplay.appendChild(entryDiv);
});
+
+ // Update pagination controls
+ const lastPage = Math.ceil(ttsList.length / itemsPerPage);
+ document.getElementById('pageIndicator').innerText = `Page ${currentPage} of ${lastPage}`;
+ document.getElementById('pageIndicator1').innerText = `Page ${currentPage} of ${lastPage}`;
+ document.getElementById('prevPage').disabled = (currentPage === 1);
+ document.getElementById('nextPage').disabled = (currentPage === lastPage);
}
+
async function generateAndPlayRemote(chunk, language, characterVoice, volume) {
try {
if (stopTTSGeneration) {
console.log("TTS generation stopped.");
return; // Early return if stop flag is set
}
- console.log("generateAndPlayRemote:", chunk);
const data = new URLSearchParams({
text_input: chunk.trim(),
text_filtering: "standard",
@@ -913,13 +1087,10 @@
src: [fileUrl],
volume: parseFloat(document.getElementById("volume").value),
onplay: function () {
- console.log('Playback started for', fileUrl);
},
onend: function () {
- console.log('Playback finished for', fileUrl);
},
onpause: function () {
- console.log('Playback paused for', fileUrl);
},
onloaderror: function (e) {
console.error('Load error for', fileUrl, ':', e);
@@ -1054,15 +1225,26 @@
function playNextLocalChunk() {
if (audioQueue.length > 0 && currentlyPlayingIndex < audioQueue.length) {
isPlaying = true;
- audioQueue[currentlyPlayingIndex++].play();
+ let currentSound = audioQueue[currentlyPlayingIndex];
+ currentSound.play();
+
+ // Once a sound finishes playing, unload it
+ currentSound.on('end', () => {
+ currentSound.unload();
+ });
+
+ currentlyPlayingIndex++;
} else {
isPlaying = false;
}
}
+
function stopPlayback() {
Howler.stop();
audioQueue = [];
+ // Unload each sound in the queue
+ audioQueue.forEach(sound => sound.unload());
currentlyPlayingIndex = 0;
isPlaying = false;
}
@@ -1102,7 +1284,6 @@
const startFromIdElement = document.getElementById('startFromId');
if (startFromIdElement) {
startFromIdElement.setAttribute('value', '1');
- console.log('Start From ID set to 1');
}
// Other initializations...
});
@@ -1122,6 +1303,7 @@
// and highlight the corresponding item
playListFromIndex(startIndex);
highlightPlaying(startIndex + 1); // Assuming the list items are 1-indexed
+ updateCurrentPage(startIndex + 1); // Update the current page based on the playing item
} else {
// If list is set to pause, pause the current item
// and remove highlighting
@@ -1154,6 +1336,26 @@
if (currentItem) {
currentItem.classList.add('highlight');
}
+ updateCurrentPage(id);
+ }
+
+
+ function updateCurrentPage(itemIndex) {
+ // Calculate the page number based on the item index
+ // Note: Ensure that the itemIndex is 1-based; if it's 0-based, add 1.
+ const newPage = Math.ceil(itemIndex / itemsPerPage);
+
+ // Update the current page and UI if the new page is different from the current page
+ if (currentPage !== newPage) {
+ currentPage = newPage; // Set the new current page
+ updateUIList(); // Refresh the list display to show the correct page
+ }
+
+ // Optionally, update the 'Jump to Page' input to reflect the current page
+ const jumpToPageInput = document.getElementById('jumpToPage');
+ if (jumpToPageInput) {
+ jumpToPageInput.value = currentPage;
+ }
}
@@ -1191,6 +1393,7 @@
console.log('Index is out of bounds, stopping playback.');
// Clear any highlights if out of bounds
highlightPlaying(null);
+ updateUIList();
}
}
@@ -1212,6 +1415,14 @@
if (startFromIdElement) {
startFromIdElement.value = '1';
}
+ const pageIndicator = document.getElementById('pageIndicator');
+ if (pageIndicator) {
+ pageIndicator.textContent = 'Page 1 of 1';
+ }
+ const pageIndicator1 = document.getElementById('pageIndicator1');
+ if (pageIndicator1) {
+ pageIndicator1.textContent = 'Page 1 of 1';
+ }
}
function editText(id) {
@@ -1424,6 +1635,70 @@
//////// General Dcoument Listeners ////////
////////////////////////////////////////////
+ // Event listeners for pagination controls
+ document.getElementById('prevPage').addEventListener('click', () => {
+ if (currentPage > 1) {
+ currentPage--;
+ updateUIList();
+ }
+ });
+
+ document.getElementById('nextPage').addEventListener('click', () => {
+ const lastPage = Math.ceil(ttsList.length / itemsPerPage);
+ if (currentPage < lastPage) {
+ currentPage++;
+ updateUIList();
+ }
+ });
+
+ // Initialize the list on page load
+ document.addEventListener('DOMContentLoaded', updateUIList);
+
+
+ // For the 'Previous' button at the bottom
+ document.getElementById('prevPage1').addEventListener('click', () => {
+ if (currentPage > 1) {
+ currentPage--;
+ updateUIList();
+ }
+ });
+
+ // For the 'Next' button at the bottom
+ document.getElementById('nextPage1').addEventListener('click', () => {
+ let lastPage = Math.ceil(ttsList.length / itemsPerPage);
+ if (currentPage < lastPage) {
+ currentPage++;
+ updateUIList();
+ }
+ });
+
+ function handleJumpButtonClick(event) {
+ // Determine which set of controls to use based on the button that was clicked
+ const suffix = event.target.id === 'jumpButton' ? '' : '1';
+ const jumpToInput = document.getElementById(`jumpToPage${suffix}`);
+ const jumpToValue = jumpToInput.value.trim(); // Get the trimmed value
+ const jumpTo = parseInt(jumpToValue, 10); // Parse the value as an integer
+
+ if (!isNaN(jumpTo)) {
+ let lastPage = Math.ceil(ttsList.length / itemsPerPage);
+
+ if (jumpTo >= 1 && jumpTo <= lastPage) {
+ currentPage = jumpTo;
+ updateUIList();
+ } else {
+ alert(`Please enter a valid page number between 1 and ${lastPage}`);
+ }
+ } else {
+ alert("Please enter a number to jump to.");
+ }
+ }
+
+ // Set up the event listener for both jump buttons
+ document.getElementById('jumpButton').addEventListener('click', handleJumpButtonClick);
+ document.getElementById('jumpButton1').addEventListener('click', handleJumpButtonClick);
+
+
+
// Event listener for changing play type
document.getElementById('playType').addEventListener('change', function () {
isStreamingMode = this.value === 'stream';
@@ -1545,11 +1820,13 @@
adjustPlaybackAndChunkSize(savedPlayType); // Adjust selectability on page load
}
- // Initialize playback based on preference
- const savedPlayMode = localStorage.getItem('playMode');
- if (savedPlayMode) {
- document.getElementById('playMode').value = savedPlayMode;
- }
+ document.addEventListener('DOMContentLoaded', function () {
+ const savedPlayMode = localStorage.getItem('playMode');
+ if (savedPlayMode) {
+ document.getElementById('playMode').value = savedPlayMode;
+ }
+ playModeValue = savedPlayMode || 'local'; // Default to 'local' if nothing is saved
+ });
// Initialize chunk size based on preference
const savedChunkSize = localStorage.getItem('chunkSize');
@@ -1665,4 +1942,4 @@