Browse Source

Initial commit with very early version

master
Macoy Madson 2 years ago
parent
commit
87fdb57d24
5 changed files with 250 additions and 0 deletions
  1. +10
    -0
      .gitignore
  2. +78
    -0
      song-sketcher-server.py
  3. +60
    -0
      song-sketcher.html
  4. +9
    -0
      webResources/song-sketcher.css
  5. +93
    -0
      webResources/song-sketcher.js

+ 10
- 0
.gitignore View File

@ -0,0 +1,10 @@
*.pyc
*URLs.txt
*.geany
output
SubmissionCache.bin
*.bin
LOCAL_*
*.sublime-workspace
*.db
*.db-journal

+ 78
- 0
song-sketcher-server.py View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.httpclient
import tornado.gen
import os
# import random
# import shutil
# import json
# import multiprocessing
#
# Tornado handlers
#
class HomeHandler(tornado.web.RequestHandler):
def get(self):
self.render('song-sketcher.html')
class UploadHandler(tornado.web.RequestHandler):
def post(self):
recording = self.request.files['recording'][0]
original_filename = recording['filename']
# TODO Actually look at what type the file is!
output_file = open('output/' + original_filename + '.ogg', 'wb')
output_file.write(recording['body'])
print('File ' + original_filename + ' uploaded')
self.finish('File ' + original_filename + ' uploaded')
#
# Startup
#
def make_app():
return tornado.web.Application([
# Home page
(r'/', HomeHandler),
# # Configure the script
# (r'/settings', SettingsHandler),
# # Handles messages for run script
# (r'/runScriptWebSocket', RunScriptWebSocket),
# # Handles messages for randomImageBrowser
# (r'/randomImageBrowserWebSocket', RandomImageBrowserWebSocket),
# Upload handler
(r'/upload', UploadHandler),
# # Don't change this 'output' here without changing the other places as well
(r'/output/(.*)', tornado.web.StaticFileHandler, {'path' : 'output'}),
# Static files. Keep this at the bottom because it handles everything else
# TODO put these in a subdir so everything isn't accessible
(r'/webResources/(.*)', tornado.web.StaticFileHandler, {'path' : 'webResources'}),
],
xsrf_cookies=True,
cookie_secret='dooblydoo')
if __name__ == '__main__':
print('\n\tWARNING: Do NOT run this server on the internet (e.g. port-forwarded)'
' nor when\n\t connected to an insecure LAN! It is not protected against malicious use.\n')
port = 8888
print('\nStarting Song Sketcher Server on port {}...'.format(port))
app = make_app()
app.listen(port)
ioLoop = tornado.ioloop.IOLoop.current()
# updateStatusCallback = tornado.ioloop.PeriodicCallback(updateScriptStatus, 100)
# updateStatusCallback.start()
ioLoop.start()

+ 60
- 0
song-sketcher.html View File

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<title>Song Sketcher</title>
<link rel="stylesheet" type="text/css" href="webResources/song-sketcher.css">
<script type="text/javascript" src="webResources/song-sketcher.js"></script>
</head>
<body>
<!-- <div id="imageBrowserControls">
<div class="leftControls">
<button class="previousImage affectOpacity" onclick="sendMessage('previousImage')">Previous Random</button>
<button class="previousImageInFolder affectOpacity" onclick="sendMessage('previousImageInFolder')">Previous In Folder</button>
<button class="previousFavorite affectOpacity" onclick="sendMessage('previousFavorite')">Previous Favorite</button>
</div>
<div class="rightControls">
<button class="nextImage affectOpacity" onclick="sendMessage('nextImage')">Next Random</button>
<button class="nextImageInFolder affectOpacity" onclick="sendMessage('nextImageInFolder')">Next In Folder</button>
<button class="nextFavorite affectOpacity" onclick="sendMessage('nextFavorite')">Next Favorite</button>
</div>
<div class="centerControls">
<input type="range" onchange="onOpacityChanged(this.value)" min="0.0" max="1.0" value="0.3" class="slider affectOpacity" step="0.1" id="opacitySlider">
<input class="filter affectOpacity" type="text" id="filter" name="filter" placeholder="Filter" oninput="filterChanged(this.value)" />
<div class="centerControlsButtons">
<button class="imageAddToFavorites affectOpacity" onclick="sendMessage('imageAddToFavorites')">Favorite</button>
<button class="changeDirectory affectOpacity" onclick="toggleDirectoryControls()">Browse Directories</button>
<button class="toggleFullScreen affectOpacity" onclick="toggleFullScreen()">Toggle Fullscreen</button>
</div>
</div>
</div>
<p class="affectOpacity" id="message"></p>
<div id="videoContainer"></div>
<div id="directoryControls" style="display:none">
<div class="directoryList">
<input type="range" onchange="onOpacityChanged(this.value)" min="0.0" max="1.0" value="0.3" class="slider affectOpacity" step="0.1" id="opacitySlider">
<input class="filter affectOpacity" type="text" id="directoryFilter" name="directoryFilter" placeholder="Filter" oninput="directoryFilterChanged(this.value)" />
<button class="affectOpacity directoryNavigationButton" onclick="toggleDirectoryControls()">Back to Random Browser</button>
<button class="affectOpacity directoryNavigationButton" onclick="directoryUpOnClick()">Up</button>
<button class="affectOpacity directoryNavigationButton" onclick="directoryRootOnClick()">Root</button>
</div>
<div id="directoryListContainer" class="directoryList"></div>
</div> -->
<button id="toggleRecord" class="toggleRecord" onclick="toggleRecord()">Record</button>
<audio controls>
<source src="output/blob.ogg" type="audio/ogg">
</audio>
<!-- Not actually in a form, but put here so that we can use it in JS -->
{% raw xsrf_form_html() %}
</body>
</html>

+ 9
- 0
webResources/song-sketcher.css View File

@ -0,0 +1,9 @@
.toggleRecord {
/* position: fixed; */
/* opacity: 0.3; */
/* left: 0; */
width: 20%;
height: 20%;
}

+ 93
- 0
webResources/song-sketcher.js View File

@ -0,0 +1,93 @@
function getUploadUrl() {
/* return "http://" + window.location.host + "/upload"; */
return "upload";
}
// from https://air.ghost.io/recording-to-an-audio-file-using-html5-and-js/
// appends an audio element to playback and download recording
function createAudioElement(blobUrl) {
const downloadEl = document.createElement('a');
downloadEl.style = 'display: block';
downloadEl.innerHTML = 'download';
downloadEl.download = 'audio.webm';
downloadEl.href = blobUrl;
const audioEl = document.createElement('audio');
audioEl.controls = true;
const sourceEl = document.createElement('source');
sourceEl.src = blobUrl;
sourceEl.type = 'audio/webm';
audioEl.appendChild(sourceEl);
document.body.appendChild(audioEl);
document.body.appendChild(downloadEl);
}
var activeRecorder = null;
function startRecording() {
// request permission to access audio stream
navigator.mediaDevices.getUserMedia({
audio: true
}).then(stream => {
// store streaming data chunks in array
const chunks = [];
// create media recorder instance to initialize recording
const recorder = new MediaRecorder(stream);
// function to be called when data is received
recorder.ondataavailable = e => {
// add stream data to chunks
chunks.push(e.data);
// if recorder is 'inactive' then recording has finished
if (recorder.state == 'inactive') {
// convert stream data chunks to a 'webm' audio format as a blob
// TODO: This doesn't actually seem to convert to webm; when sent to the server it's ogg
const blob = new Blob(chunks, {
type: 'audio/webm'
});
// convert blob to URL so it can be assigned to a audio src attribute
createAudioElement(URL.createObjectURL(blob));
// Upload to server
var formData = new FormData();
formData.append("recording", blob);
formData.append("_xsrf", document.getElementsByName("_xsrf")[0].value);
var uploadRequest = new XMLHttpRequest();
// TODO: HTTPS
uploadRequest.open('POST', getUploadUrl(), true);
/* var contentType = "multipart/form-data; boundary=" + boundary; */
/* var contentType = "multipart/form-data"; */
/* uploadRequest.setRequestHeader("Content-Type", contentType); */
uploadRequest.send(formData);
}
};
// start recording with 1 second time between receiving 'ondataavailable' events
recorder.start(1000);
activeRecorder = recorder;
// setTimeout to stop recording after 4 seconds
/* setTimeout(() => {
// this will trigger one final 'ondataavailable' event and set recorder state to 'inactive'
recorder.stop();
}, 4000); */
}).catch(console.error);
}
function stopRecording() {
if (activeRecorder) {
activeRecorder.stop();
activeRecorder = null;
}
}
function getElement(id) {
return document.getElementById(id);
}
function toggleRecord() {
if (activeRecorder) {
stopRecording();
getElement("toggleRecord").innerHTML = "Record";
} else {
startRecording();
getElement("toggleRecord").innerHTML = "Stop Recording";
}
}

Loading…
Cancel
Save