prod-changes

This commit is contained in:
otrs 2017-10-23 21:10:42 +02:00
parent d24cef2b51
commit 217603823e
5 changed files with 3012 additions and 35 deletions

View File

@ -33,7 +33,7 @@ def index(sound=None, text=None, video=None):
pitch = request.form.get("pitch", default="") pitch = request.form.get("pitch", default="")
pitch = pitch if pitch.strip() != "" else "50" pitch = pitch if pitch.strip() != "" else "50"
subprocess.Popen(["espeak", "-v", voice, "-s", speed, "-p", pitch, text], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) subprocess.Popen(["espeak", "-v", voice, "-s", speed, "-p", pitch, text.encode('utf-8')], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return redirect("/") return redirect("/")
video = request.args.get("video") video = request.args.get("video")

2801
static/howler.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,11 +20,11 @@ h1 {
} }
form { form {
padding: 5px;
text-align: center; text-align: center;
display: inline;
} }
input { input, button {
background-color: #666; background-color: #666;
border: 1px solid #999; border: 1px solid #999;
border-radius: 5px; border-radius: 5px;
@ -34,6 +34,21 @@ input {
vertical-align: middle; vertical-align: middle;
} }
button {
margin: 5px;
}
button:hover {
background-color: #999;
border: 1px solid #666;
}
button:active {
background-color: #999;
border: 1px solid #666;
color: #000;
}
label { label {
vertical-align: middle; vertical-align: middle;
} }
@ -65,12 +80,14 @@ section {
width: 100%; width: 100%;
} }
#reset { div #reset {
font-size: 2em; font-size: 2em;
padding-left: 5px; padding-left: 5px;
display: inline;
vertical-align: middle;
} }
#reset:hover { div #reset:hover {
cursor: pointer; cursor: pointer;
} }
@ -96,6 +113,29 @@ section {
} }
.sound a:hover { .sound a:hover {
background-color: #ff4136; cursor: pointer;
box-shadow: inset 5px 5px 5px rgba(0, 0, 0, 0.6); }
.sound a:active {
background-color: #ff4136;
box-shadow: inset 5px 5px 5px rgba(0, 0, 0, 0.6);
cursor: pointer;
}
.sound-pressed {
background-color: #ff4136 !important;
box-shadow: inset 5px 5px 5px rgba(0, 0, 0, 0.6) !important;
}
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#local-mode-button .local {
color: red;
} }

View File

@ -1,3 +1,9 @@
var localModeEnabled = false;
// References to howler objects
var howlerSounds = [];
function ready(fn) { function ready(fn) {
if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") { if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
fn(); fn();
@ -6,9 +12,11 @@ function ready(fn) {
} }
} }
ready(function() { function sleep(ms) {
hideSections(); return new Promise(resolve => setTimeout(resolve, ms));
}
ready(function() {
var sections = document.querySelectorAll("section"); var sections = document.querySelectorAll("section");
var nav = document.querySelectorAll("nav a"); var nav = document.querySelectorAll("nav a");
@ -28,9 +36,9 @@ ready(function() {
}); });
var searchfield = document.querySelector("#search"); var searchfield = document.querySelector("#search");
searchfield.focus();
searchfield.addEventListener("keyup", function() { searchfield.addEventListener("keyup", function() {
console.log("Search!");
var buttons = document.querySelectorAll(".sound"); var buttons = document.querySelectorAll(".sound");
@ -48,18 +56,77 @@ ready(function() {
}); });
var reset = document.querySelector("#reset"); var reset = document.querySelector("#reset");
var sounds_nav = document.querySelector("#sounds-nav");
reset.addEventListener("click", function() { reset.addEventListener("click", resetSearch, false);
var buttons = document.querySelectorAll(".sound"); sounds_nav.addEventListener("click", resetSearch, false);
buttons.forEach(function(item) { addKeyListeners();
item.style.display = "inline-block";
});
searchfield.value = "";
});
}); });
/*
* Adds all necessary KeyListeners to document
*/
function addKeyListeners() {
// keyboard listener for global key strokes/inputs
document.onkeydown = function(evt) {
evt = evt || window.event;
if (evt.keyCode == 27) {
// esc key
resetSearch();
} else if ((evt.keyCode == 75 || evt.keyCode == 67) && evt.ctrlKey) {
// ctrl+k and ctrl+c key binding
killAllAudio();
} else if (evt.keyCode == 88 && evt.ctrlKey){
// ctrl+x key binding
toggleLocalMode();
}
};
// keyboard listener for playing sounds using enter key
var buttons = document.querySelectorAll(".sound");
buttons.forEach(function(item) {
item.firstChild.addEventListener('keypress', async function (e) {
var key = e.keyCode;
var source = e.target;
// keylistener for enter or ctrl+enter (which is k10 on chrome)
if (key === 13 || (key === 10 && e.ctrlKey)) {
if(e.ctrlKey){
killAllAudio();
await sleep(100);
}
source.classList.add("sound-pressed");
source.onclick();
await sleep(300);
source.classList.remove("sound-pressed");
}
});
});
}
function resetSearch() {
var searchfield = document.querySelector("#search");
var buttons = document.querySelectorAll(".sound");
buttons.forEach(function(item) {
item.style.display = "inline-block";
});
searchfield.value = "";
searchfield.focus();
}
/*
* Reads the stream url from input with id #streaming-url and forwards it to the server using AJAX.
*/
function playStream() {
var streamUrl = document.querySelector("#streaming-url").value;
ajaxRequest("/?video="+encodeURI(streamUrl));
}
function hideSections() { function hideSections() {
var sections = document.querySelectorAll("section"); var sections = document.querySelectorAll("section");
@ -67,3 +134,68 @@ function hideSections() {
item.style.display = "none"; item.style.display = "none";
}); });
} }
function ajaxRequest(url) {
var ajaxRequest;
try{
ajaxRequest = new XMLHttpRequest();
ajaxRequest.open("GET", url, true);
ajaxRequest.send(null);
}catch (e){
alert("Unfortunately we were unable to handle your request. Please try again later and contact the server administrator if the problem persists.");
return false;
}
}
/*
* Switches between local and remote playback mode.
* Additionally changes the button text and its color so that the user has a visible feedback.
*/
function toggleLocalMode() {
toggleButton = document.getElementById("local-mode-button").children[0];
if(localModeEnabled){
localModeEnabled = false;
toggleButton.classList.remove("local");
toggleButton.innerHTML = "[S]";
toggleButton.title = "play sounds on server";
}else{
localModeEnabled = true;
toggleButton.classList.add("local");
toggleButton.innerHTML = "[L]";
toggleButton.title = "play sounds locally";
}
}
/*
* Either plays the given sound file locally by using howler.js or forwards the request to the remote server using AJAX.
*/
function playSound(filename) {
if(localModeEnabled){
// play local audio using howler.js
var sound = new Howl({
src: ['/sounds/'+filename]
});
sound.play();
howlerSounds.push(sound);
}else{
ajaxRequest("/play/"+filename);
}
}
function killAllHowlerAudio() {
for(i=0; i<howlerSounds.length; i++) {
howlerSounds[i].stop();
}
}
/*
* Kills all local or remote audio, depending on localModeEnabled
*/
function killAllAudio() {
if (localModeEnabled) {
killAllHowlerAudio();
} else {
ajaxRequest("/?killvideo=yes");
}
}

View File

@ -30,29 +30,32 @@
</head> </head>
<body> <body>
<nav> <nav>
<a href="#sounds">Sounds</a> <a href="#sounds" id="sounds-nav">Sounds</a>
<a href="#youtube">YouTube</a> <a href="#streams">Streams</a>
<a href="#voice">Voice</a> <a href="#voice">Voices</a>
</nav> </nav>
<content> <content>
<section id="sounds"> <section id="sounds" style="display:none;">
<div><input type="text" id="search" /><span id="reset"></span></div> <div>
<a onclick="toggleLocalMode();" id="local-mode-button"><button title="play sounds on server">[S]</button></a>
<input type="text" id="search" autofocus/>
<div id="reset"></div>
</div>
{% for sound in sounds %} {% for sound in sounds %}
<div class="sound"><a href="{{ '/play/' + sound | urlencode }}">{{ sound.split('.', 1)[0] }}</a></div> <div class="sound"><a tabindex="0" class="unselectable" onclick="playSound('{{ sound | urlencode }}');">{{ sound.split('.', 1)[0] }}</a></div>
{% endfor %} {% endfor %}
</section> </section>
<section id="youtube"> <section id="streams" style="display:none;">
<form action="/" method="GET"> <div>
<label for="video">YouTube URL</label> <form>
<input type="text" name="video" /> <label for="video">Stream URL</label>
<input type="submit" value="Play" /> <input id="streaming-url" type="text" name="video" placeholder="paste stream url here..." />
</form> </form>
<form action="/" method="GET"> <button onclick="playStream();">Play!</button>
<input type="hidden" name="killvideo" value="yes" /> </div>
<input type="submit" name="submit" value="Terminate videos" /> <button name="submit" onclick="killAllAudio();">Terminate videos</button>
</form>
</section> </section>
<section id="voice"> <section id="voice" style="display:none;">
<form action="/say/" method="POST"> <form action="/say/" method="POST">
<input type="text" name="text" /> <input type="text" name="text" />
<input type="text" name="voice" placeholder="DE" /> <input type="text" name="voice" placeholder="DE" />
@ -64,6 +67,7 @@
</form> </form>
</section> </section>
</content> </content>
<script src="/static/howler.js"></script>
<script src="/static/main.js"></script> <script src="/static/main.js"></script>
</body> </body>
</html> </html>