Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Save scroll position so you continue from wherever you left off at a given folder level. Add keyboard shortcuts (need fixing, sees search input). Add "love" with logging to var/ |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | master | trunk |
Files: | files | file ages | folders |
SHA3-256: | 31f5dff3856da44d8017c865339075aa |
User & Date: | ajv-899-334-8894@vsta.org 2018-03-13 01:44:42 |
Context
2018-03-13
| ||
01:50 | Don't use global keystroke shortcuts when it's input. check-in: b93e987eac user: ajv-899-334-8894@vsta.org tags: master, trunk | |
01:44 | Save scroll position so you continue from wherever you left off at a given folder level. Add keyboard shortcuts (need fixing, sees search input). Add "love" with logging to var/ check-in: 31f5dff385 user: ajv-899-334-8894@vsta.org tags: master, trunk | |
2017-11-22
| ||
04:21 | Embrace ES6 now that we can play flac on FF using transcoding. Shorten playlist entries when they have a common path. check-in: bc0d6d6ec2 user: ajv-899-334-8894@vsta.org tags: master, trunk | |
Changes
Changes to html/top.html.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<button onclick="return seek(-600);">-10m</button> <button onclick="return seek(-60);">-1m</button> <button onclick="return seek(-10);">-10s</button> <button onclick="return seek(10);">+10s</button> <button onclick="return seek(60);">+1m</button> <button onclick="return seek(600);">+10m</button> <button onclick="return playNext();">>next</button> </td> </tr> </table> <hr> <button onclick="return go_up();"> <img src="/imgs/player_eject.png" alt="Go Up" /> </button> |
> > |
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<button onclick="return seek(-600);">-10m</button> <button onclick="return seek(-60);">-1m</button> <button onclick="return seek(-10);">-10s</button> <button onclick="return seek(10);">+10s</button> <button onclick="return seek(60);">+1m</button> <button onclick="return seek(600);">+10m</button> <button onclick="return playNext();">>next</button> <button onclick="return shuffle();">shufl</button> <button onclick="return loveit();" id="lovebtn">love</button> </td> </tr> </table> <hr> <button onclick="return go_up();"> <img src="/imgs/player_eject.png" alt="Go Up" /> </button> |
Changes to js/player.js.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 .. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 ... 107 108 109 110 111 112 113 114 115 116 117 118 119 120 ... 184 185 186 187 188 189 190 191 192 193 194 195 196 197 ... 239 240 241 242 243 244 245 246 247 248 249 250 251 252 ... 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 ... 331 332 333 334 335 336 337 338 339 340 341 342 343 |
var path = ""; var pdepth = 0; // Are we within a tree with a file index? var indexed = false; // This will be path's contents; it goes to null while // it's getting new content for the current path var pcontents = null; // Do we have something on the turntable right now? var playing = false; // One-time parse of base URL to find any player options // Note we don't do any defense here, because the URL is under the // remote user's control, but it's only their own browser's JS which ................................................................................ opts[item[0]] = true; } else { opts[item[0]] = item[1]; } }); }; urlOpts(); // Answer back on dir contents function gotDir(req) { var d, f, res; // Connection progress if ((req.readyState != 4) || (req.status != 200)) { ................................................................................ res += ' <img src="/imgs/player_play.png" alt="play" />\n' res += '</button>' + unescape(f) + '<br>\n' } } // Replace the HTML browser.innerHTML = res; } // Invert a path and make it friendlier to small screens function do_trim(s) { var idx, elem, res = ''; while (s.length > 0) { ................................................................................ if (newTime >= 0) { player.currentTime = newTime; } } // End of current track, try to advance function playNext() { if (playlist.length > 0) { var s = playlist.shift(); player.src = s; // For good measure player.play(); ................................................................................ // If looking at search filter, "up" means back out // of this filtered view if (searchval.value != "") { searchval.value = ""; curdir(); return false; } // Otherwise pop up a directory level var idx = path.lastIndexOf("/"); path = path.slice(0, idx); pdepth -= 1; curdir(); ................................................................................ // Push to dir function go_dir(didx) { // Working on a previous click if (pcontents == null) { return false; } path = path + "/" + pcontents.dirs[didx]; pdepth += 1; searchval.value = ""; curdir(); return false; } // Back to top of tree function go_top() { path = ""; pdepth = 0; curdir(); return false; } // Incremental search ................................................................................ // Get a set of options based on the current path // and search value var url = "/search" + path + "?q=" + escape(s); pdepth += 1; getDir(url); } // Set up the player player.addEventListener("ended", playNext); // Initial browser window update curdir(); |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 .. 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 ... 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 ... 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 ... 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 ... 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 ... 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
var path = ""; var pdepth = 0; // Are we within a tree with a file index? var indexed = false; // This will be path's contents; it goes to null while // it's getting new content for the current path var pcontents = null; // This maps a given path to our last scroll position within it var pscroll = {}; // Do we have something on the turntable right now? var playing = false; // One-time parse of base URL to find any player options // Note we don't do any defense here, because the URL is under the // remote user's control, but it's only their own browser's JS which ................................................................................ opts[item[0]] = true; } else { opts[item[0]] = item[1]; } }); }; urlOpts(); // Note current scroll position WRT current path function markpos() { if (searchval.value == '') { var scroller = document.scrollingElement; pscroll[path] = scroller.scrollTop; } } // Restore to scroll position function gopos() { if (searchval.value != '') { return; } if (path in pscroll) { var d = document.scrollingElement; d.scrollTop = pscroll[path]; } } // Answer back on dir contents function gotDir(req) { var d, f, res; // Connection progress if ((req.readyState != 4) || (req.status != 200)) { ................................................................................ res += ' <img src="/imgs/player_play.png" alt="play" />\n' res += '</button>' + unescape(f) + '<br>\n' } } // Replace the HTML browser.innerHTML = res; // Auto-scroll, but leave search alone gopos(); } // Invert a path and make it friendlier to small screens function do_trim(s) { var idx, elem, res = ''; while (s.length > 0) { ................................................................................ if (newTime >= 0) { player.currentTime = newTime; } } // End of current track, try to advance function playNext() { lovebtn.style.background = ""; if (playlist.length > 0) { var s = playlist.shift(); player.src = s; // For good measure player.play(); ................................................................................ // If looking at search filter, "up" means back out // of this filtered view if (searchval.value != "") { searchval.value = ""; curdir(); return false; } // It's a "real" up, note position so if we come back down, // we'll still be at this position. markpos(); // Otherwise pop up a directory level var idx = path.lastIndexOf("/"); path = path.slice(0, idx); pdepth -= 1; curdir(); ................................................................................ // Push to dir function go_dir(didx) { // Working on a previous click if (pcontents == null) { return false; } markpos(); path = path + "/" + pcontents.dirs[didx]; pdepth += 1; searchval.value = ""; curdir(); return false; } // Back to top of tree function go_top() { markpos(); path = ""; pdepth = 0; curdir(); return false; } // Incremental search ................................................................................ // Get a set of options based on the current path // and search value var url = "/search" + path + "?q=" + escape(s); pdepth += 1; getDir(url); } // Shuffle current playlist function shuffle() { var idx, other, idx, hold; var l = playlist.length; for (idx = 0; idx < l; ++idx) { other = Math.floor(Math.random() * l); hold = playlist[idx]; playlist[idx] = playlist[other]; playlist[other] = hold; } paintQueue(); return false; } // Note a track we like function loveit() { if (!playing) { return; } lovebtn.style.background = "pink"; var ob = {"url": player.src}; var req = new XMLHttpRequest(); req.open("PUT", "/love.json"); req.send(JSON.stringify(ob)); } // Set up the player player.addEventListener("ended", playNext); // A few keyboard shortcuts document.onkeypress = function(e) { e = e || window.event; var kc = e.keyCode; // 'b', go back if (kc == 98) { go_up(); // 't', go to top } else if (kc == 116) { var d = document.scrollingElement; d.scrollTop = 0; } else { console.log("Unknown keystroke: " + kc.toString()); } } // Initial browser window update curdir(); |
Changes to main.py.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# main.py # Main driver for WWW-Usenet interface # import sys, time, os import chore import utils from get import GET_mixin from chore.authen import Authen_mixin, Authen_Server_mixin # Tie our various handlers together class App_Handler(chore.handlers.Chore_Handler, GET_mixin, Authen_mixin): def __init__(self, conn, tup, approot): chore.handlers.Chore_Handler.__init__(self, conn, tup, approot, (GET_mixin.__init__, Authen_mixin.__init__)) # Load our configuration file # # This includes configuring our config file elements, # then processing the supplied file. def load_cfg(fn): |
> | > |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# main.py # Main driver for WWW-Usenet interface # import sys, time, os import chore import utils from get import GET_mixin from put import PUT_mixin from chore.authen import Authen_mixin, Authen_Server_mixin # Tie our various handlers together class App_Handler(chore.handlers.Chore_Handler, GET_mixin, PUT_mixin, Authen_mixin): def __init__(self, conn, tup, approot): chore.handlers.Chore_Handler.__init__(self, conn, tup, approot, (GET_mixin.__init__, PUT_mixin.__init__, Authen_mixin.__init__)) # Load our configuration file # # This includes configuring our config file elements, # then processing the supplied file. def load_cfg(fn): |
Deleted post.py.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# # post.py # HTML POST/PUT handling # # POST's put state back to us--usually a text to send. # # / - An old-skool Form submit; non-JS browser # /msg.json - JSON of a message to send # import json from utils import toascii class POST_mixin(object): # Write @buf's contents to the file named @fn def putfile(self, fn, buf): f = open(fn, "w") f.write(buf) f.close() # Send a message def post_msg(self, buf): # Burst from JSON msg = json.loads(buf) towhom = toascii(msg.get("recipient", "")) body = toascii(msg.get("body", "")) # Malformed? if (not towhom) or (not body): self.send_error(404) return None # Recipient known? user = self.user acct = user.roster.get(towhom) if acct is None: self.send_error(404) return None # Send message with user.exclusion: print "Send msg", towhom, body acct.send(towhom, body) # Log a message on our own display for tup in reversed(user.msgs): if tup[1] != '>': break if towhom == tup[1]: # "mFrom" is what gets displayed, so populate it with # either '>' (last sender) or actual name user.add('>', towhom, body) else: user.add('> ' + towhom, towhom, body) # Empty result body self.send_result("") return "" # Entry from an HTML POST, body already read # and in @buf def handle_post(self, buf): p = self.path # Burst path pp = p.strip("/").split("/") # Operation on root; Form submit, so probably an old # non-JS browser sending a message. if (len(pp) == 1) and (not pp[0]): print "TBD: POST to root" # return self.post_root(buf) self.send_error(404) return None # JS submission of text to post if (len(pp) == 1) and (pp[0] == "msg.json"): return self.post_msg(buf) # Unknown submission type self.send_error(404) return None |
< < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added put.py.
> > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# # put.py # HTML PUT handling # # /love.json # Flag a track (well, URL) of something we like # import json class PUT_mixin(object): # URL handlers def __init__(self): self.dispatchers.append( ("PUT", self.loveit) ) # Accept a love'ed track and log to this user def loveit(self, buf): d = json.loads(buf) f = open("var/" + self.user + ".loves", "a") f.write(d["url"]) f.write("\n") f.close() return True,self.send_result("", "text/html") |