From a0c40ef52ef55beba914b6244e17f02c5cf33c61 Mon Sep 17 00:00:00 2001 From: Matthew Woodward Date: Wed, 14 Apr 2021 01:16:15 -0500 Subject: [PATCH] Functioning prototype of command mode. Many more commands to be added --- main.js | 316 ++++++++++++++++++++++++++---------- modules.js/SelectionMenu.js | 16 +- 2 files changed, 238 insertions(+), 94 deletions(-) diff --git a/main.js b/main.js index 17fd3a1..32efd86 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -// mpvDLNA 1.0.0 +// mpvDLNA 1.1.0 "use strict"; @@ -108,10 +108,35 @@ var DLNA_Browser = function(options) { this.typing_text = ""; this.autocomplete = []; this.selected_auto = {id: 0, full: ""}; + + this.commands = { + "scan" : { func: function(self){ self.menu.showMessage("Scanning"); + self.findDLNAServers(); + self.menu.showMessage("Scan Complete"); }, + args: [], + text: false}, + + "cd" : { func: function(self, file) { self.command_cd(file); }, + args: [], + text: true}, + + "test" : { func: function(self, file){ mp.msg.error("test"); }, + args: [], + text: true} + }; + this.command_list = Object.keys(this.commands); + + // String key of the current command + this.command = null; }; DLNA_Browser.prototype.findDLNAServers = function() { + this.scan = false; + this.menu.title = "Scanning for DLNA Servers"; + this.menu.renderMenu("", 1); + + mp.msg.info("scanning for dlna servers"); this.servers = []; @@ -134,6 +159,8 @@ DLNA_Browser.prototype.findDLNAServers = function() { this.menu.title = "Servers"; this.current_folder = this.servers; this.menu.setOptions(this.servers, 0); + + this.menu.renderMenu("", 1); }; @@ -143,19 +170,12 @@ DLNA_Browser.prototype.toggle = function() { if (this.menu.menuActive) { this.menu.hideMenu(); } else { - + this.menu.showMenu(); // Determine if we need to scan for DLNA servers if (this.scan) { this.menu.title = "Scanning for DLNA Servers"; - this.menu.renderMenu(); - this.menu.showMenu(); - this.findDLNAServers(); - this.scan = false; } - - this.menu.renderMenu(); - this.menu.showMenu(); } }; @@ -200,15 +220,48 @@ DLNA_Browser.prototype.toggle_typing = function(mode) { }; DLNA_Browser.prototype.typing_action = function(key) { - if (key == "backspace") { - this.typing_text = this.typing_text.slice(0, this.typing_position-1) + + if (key.length == 1){ + // "\" does not play nicely with the formatting characters in the osd message + if (key != "\\") { + this.typing_text = this.typing_text.slice(0, this.typing_position) + + key + this.typing_text.slice(this.typing_position); + this.typing_position+=1; + } + } else if (key == "backspace") { + // can't backspace if at the start of the line + if (this.typing_position) { + this.typing_text = this.typing_text.slice(0, this.typing_position-1) + this.typing_text.slice(this.typing_position); - this.typing_position-=1; + + this.typing_position-= 1; + } + + if (this.typing_mode == "command" && this.command != null) { + if (this.typing_position <= this.command.length) { + this.command = null; + } + } } else if (key == "delete") { this.typing_text = this.typing_text.slice(0, this.typing_position) + this.typing_text.slice(this.typing_position+1); + if (this.typing_mode == "command" && this.command != null) { + if (this.typing_position <= this.command.length) { + this.command = null; + + // Because we autoadd a space when completing a command and because + // using delete means the cursor is not next to it, the space becomes + // almost impossible to find. I wrote this code and still thought it + // was a bug when the invisible space character supressed the autocorrect + // Much easier for users to just not have to deal with it + if (this.typing_text[this.typing_text.length-1] == " ") { + this.typing_text = this.typing_text.slice(0, -1); + } + } + } + } else if (key == "right") { this.typing_position += 1; if (this.typing_position > this.typing_text.length) { @@ -226,8 +279,10 @@ DLNA_Browser.prototype.typing_action = function(key) { if (this.selected_auto.id >= this.autocomplete.length) { this.selected_auto.id = 0; } - this.selected_auto.full = this.autocomplete[this.selected_auto.id].full; - mp.msg.error("auto_index: " + this.selected_auto.id); + + if (this.autocomplete.length) { + this.selected_auto.full = this.autocomplete[this.selected_auto.id].full; + } } else if (key == "clear"){ this.typing_text = ""; @@ -235,13 +290,6 @@ DLNA_Browser.prototype.typing_action = function(key) { this.autocomplete = []; this.selected_auto = {id: 0, full: ""}; - } else if (key.length == 1){ - // "\" does not play nicely with the formatting characters in the osd message - if (key != "\\") { - this.typing_text = this.typing_text.slice(0, this.typing_position) - + key + this.typing_text.slice(this.typing_position); - this.typing_position+=1; - } } var message = ""; @@ -249,43 +297,40 @@ DLNA_Browser.prototype.typing_action = function(key) { message += Ass.yellow(true) + "|"; message += Ass.white(true) + this.typing_text.slice(this.typing_position); - // Use command mode autocorrect. This hasn't been implemented yet + // Use command mode autocorrect. if (this.typing_mode == "command") { - message = "$ " + message; - // Use text mode autocorrect. This will probably be broken out into a function at some point - } else if (this.typing_mode == "text") { + // Look for a valid command + if (this.command == null) { + if (this.typing_text[this.typing_text.length-1] == " ") { + var search = this.selected_auto.full; - this.autocomplete = []; - for (var i = 0; i < this.current_folder.length; i++) { - var item = this.current_folder[i]; - var index = item.name.toUpperCase().indexOf(this.typing_text.toUpperCase()) - - if ((item.children == null || item.children.length != 0) && index != -1) { - this.autocomplete.push({ - pre: item.name.slice(0, index), - post: item.name.slice(index + this.typing_text.length), - full: item.name - }); + for (var i = 0; i < this.command_list.length; i++) { + if (this.command_list[i].toUpperCase() == search.toUpperCase()) { + this.command = this.command_list[i]; + break; + } + } + + // autocomplete the command + } else { + message = this.autocomplete_command(this.typing_text, message); } } - if (this.autocomplete.length > 0) { - var search = this.selected_auto.full; - this.selected_auto = {id: 0, full: this.autocomplete[0].full}; + // Have a valid command, autocomplete the argument + if (this.command){ + var argument = this.typing_text.slice(this.typing_text.split(" ")[0].length+1); + var index = message.split(" ")[0].length+1; + var msg = message.slice(index); + message = message.slice(0, index) + this.autocomplete_text(argument, msg); + } - for (var i = 0; i < this.autocomplete.length; i++) { - if (search == this.autocomplete[i].full) { - this.selected_auto = {id: i, full: this.autocomplete[i].full}; - break; - } - } + message = "$ " + message; - message = Ass.alpha("DDDD6E") + this.autocomplete[this.selected_auto.id].pre - + Ass.alpha("00") + message + Ass.alpha("DDDD6E") + this.autocomplete[this.selected_auto.id].post; - } else { - this.selected_auto = {id: 0, full:""}; - } + // Use text mode autocorrect. + } else if (this.typing_mode == "text") { + message = this.autocomplete_text(this.typing_text, message); } message = Ass.startSeq(true) + message + Ass.stopSeq(true); @@ -304,47 +349,39 @@ DLNA_Browser.prototype.typing_parse = function() { // ep - find episode by number (maybe have option for absolute episode number instead of just its place in a season) // pep - ep but starts playback // info - query DLNA server for metadata + // text - switch to text input mode if (this.typing_mode == "command") { - if (this.typing_text == "scan") { - if (this.menu.menuActive){ - this.menu.title = "Scanning for DLNA Servers"; - this.menu.renderMenu(); - this.menu.showMenu(); - } - this.scan = false; - this.findDLNAServers(); - success = true; + // This flag is used to make sure we don't accidentally autocomplete the command + // and the arguments in a single enter keystroke + var text_input = false; + if (this.command == null) { + text_input = true; + if (this.autocomplete.length != 0) { + this.command = this.selected_auto.full + this.typing_text = this.selected_auto.full + " "; + this.typing_position = this.typing_text.length; - if (this.menu.menuActive){ - this.menu.renderMenu(); - this.menu.showMenu(); + text_input = this.commands[this.command].text; } } - } else if (this.typing_mode == "text") { - if (this.typing_text.length == 0) { - success = this.select(this.menu.getSelectedItem()); - - } else if(this.typing_text == "..") { - this.back(); - }else { - var search = this.typing_text; - if (this.autocomplete.length != 0) { - search = this.selected_auto.full; - } - for (var i = 0; i < this.current_folder.length; i++) { - var item = this.current_folder[i]; + if (this.command != null && !text_input) { + var cmd = this.commands[this.command]; - if (search == item.name) { - success = this.select(item); - } + if ( (!cmd.text && cmd.args.length == 0) || this.autocomplete.length != 0) { + this.commands[this.command].func(this, this.selected_auto.full); + success = true; } } + + } else if (this.typing_mode == "text") { + success = this.command_cd(this.typing_text); } if (success) { + this.command = null; this.typing_action("clear"); } else { // Rescan for autocomplete @@ -352,6 +389,120 @@ DLNA_Browser.prototype.typing_parse = function() { } }; +DLNA_Browser.prototype.autocomplete_command = function(text, message) { + this.autocomplete = []; + + if (text == "") { + this.selected_auto = {id: null, full: ""}; + return message; + } + + for (var i = 0; i < this.command_list.length; i++) { + var index = this.command_list[i].toUpperCase().indexOf(text.toUpperCase()); + + if (index != -1) { + this.autocomplete.push({ + pre: this.command_list[i].slice(0, index), + post: this.command_list[i].slice(index + text.length), + full: this.command_list[i], + }); + } + } + + if (this.autocomplete.length > 0) { + var search = this.selected_auto.full; + this.selected_auto = this.autocomplete[0]; + this.selected_auto.id = 0; + + for (var i = 0; i < this.autocomplete.length; i++) { + if (search == this.autocomplete[i].full) { + this.selected_auto = this.autocomplete[i]; + this.selected_auto.id = i; + break; + } + } + + message = Ass.alpha("DDDD6E") + this.selected_auto.pre + + Ass.alpha("00") + message + Ass.alpha("DDDD6E") + this.selected_auto.post; + } else { + this.selected_auto = {id: null, full: ""}; + } + + return message; +} + +DLNA_Browser.prototype.autocomplete_text = function(text, message) { + this.autocomplete = []; + + // add ".." to the list of autocomplete options + var options = this.current_folder.concat({name: ".."}); + + for (var i = 0; i < options.length; i++) { + var item = options[i]; + var index = item.name.toUpperCase().indexOf(text.toUpperCase()); + + if ((item.children == null || item.children.length != 0) && index != -1) { + this.autocomplete.push({ + pre: item.name.slice(0, index), + post: item.name.slice(index + text.length), + full: item.name, + findex: i + }); + } + } + + if (this.autocomplete.length > 0) { + var search = this.selected_auto.full; + this.selected_auto = this.autocomplete[0]; + this.selected_auto.id = 0 + + for (var i = 0; i < this.autocomplete.length; i++) { + if (search == this.autocomplete[i].full) { + this.selected_auto = this.autocomplete[i]; + this.selected_auto.id = i; + + break; + } + } + + // Update the menu selection to match + this.menu.selectionIdx = this.selected_auto.findex; + this.menu.renderMenu("", 1); + + message = Ass.alpha("DDDD6E") + this.selected_auto.pre + + Ass.alpha("00") + message + Ass.alpha("DDDD6E") + this.selected_auto.post; + } else { + this.selected_auto = {id: 0, full: ""}; + } + + return message; +} + + +DLNA_Browser.prototype.command_cd = function(text) { + var success = false; + if(text == "..") { + this.back(); + success = true; + }else { + var search = text; + if (this.autocomplete.length != 0) { + search = this.selected_auto.full; + } + + for (var i = 0; i < this.current_folder.length; i++) { + var item = this.current_folder[i]; + + if (search == item.name) { + success = this.select(item); + } + } + } + + return success +} + + // This function adds the previous and next episodes to the playlist, // changes the window title to the current episode title, and @@ -544,10 +695,7 @@ DLNA_Browser.prototype.select = function(selection) { success = true; } - if (this.menu.menuActive) { - this.menu.renderMenu(); - } - + this.menu.renderMenu("", 1); return success; } @@ -564,9 +712,7 @@ DLNA_Browser.prototype.back = function() { this.generateMenuTitle(this.titles[this.titles.length-1]); } - if (this.menu.isMenuActive()) { - this.menu.renderMenu(); - } + this.menu.renderMenu("", 1); } DLNA_Browser.prototype._registerCallbacks = function() { diff --git a/modules.js/SelectionMenu.js b/modules.js/SelectionMenu.js index 0913005..39f41f9 100644 --- a/modules.js/SelectionMenu.js +++ b/modules.js/SelectionMenu.js @@ -376,10 +376,8 @@ SelectionMenu.prototype._renderActiveText = function() if (!this.active) return; - if (this.menuActive) { - // Determine which text to render (critical messages take precedence). - var msg = this.isShowingMessage ? this.currentMessageText : this.currentMenuText; - } + // Determine which text to render (critical messages take precedence). + var msg = this.isShowingMessage ? this.currentMessageText : (this.menuActive ? this.currentMenuText : ''); if (typeof msg !== 'string') msg = ''; @@ -495,7 +493,7 @@ SelectionMenu.prototype.renderMenu = function(selectionPrefix, renderMode) // the menu is closed or busy showing a text message); 2 = Don't show/redraw // at all (good for just updating the text cache silently); any other value // (incl. undefined, aka default) = show/redraw the menu. - if ((renderMode === 1 && (!this.isMenuActive() || this.isShowingMessage)) || renderMode === 2) + if ((renderMode === 1 && (!this.menuActive || this.isShowingMessage)) || renderMode === 2) return; this.showMenu(); }; @@ -568,8 +566,8 @@ SelectionMenu.prototype.showMenu = function() if (!this.active) this.show(); - else - this._renderActiveText(); + + this._renderActiveText(); }; SelectionMenu.prototype.hideMenu = function() @@ -591,8 +589,8 @@ SelectionMenu.prototype.showTyping = function() if (!this.active) this.show(); - else - this._renderActiveText(); + + this._renderActiveText(); }; SelectionMenu.prototype.hideTyping = function()