Gilles Boccon-Gibod | aba1ac0 | 2023-08-07 11:34:58 -0700 | [diff] [blame] | 1 | <html> |
| 2 | |
| 3 | <head> |
| 4 | <style> |
| 5 | * { |
| 6 | font-family: sans-serif; |
| 7 | } |
| 8 | </style> |
| 9 | </head> |
| 10 | <body> |
| 11 | Server Port <input id="port" type="text" value="8989"></input> <button id="connectButton" onclick="connect()">Connect</button><br> |
| 12 | <div id="socketState"></div> |
| 13 | <br> |
| 14 | <div id="buttons"></div><br> |
| 15 | <hr> |
| 16 | <button onclick="onGetPlayStatusButtonClicked()">Get Play Status</button><br> |
| 17 | <div id="getPlayStatusResponseTable"></div> |
| 18 | <hr> |
| 19 | <button onclick="onGetElementAttributesButtonClicked()">Get Element Attributes</button><br> |
| 20 | <div id="getElementAttributesResponseTable"></div> |
| 21 | <hr> |
| 22 | <table> |
| 23 | <tr> |
| 24 | <b>VOLUME</b>: |
| 25 | <button onclick="onVolumeDownButtonClicked()">-</button> |
| 26 | <button onclick="onVolumeUpButtonClicked()">+</button> |
| 27 | <span id="volumeText"></span><br> |
| 28 | </tr> |
| 29 | <tr> |
| 30 | <td><b>PLAYBACK STATUS</b></td><td><span id="playbackStatusText"></span></td> |
| 31 | </tr> |
| 32 | <tr> |
| 33 | <td><b>POSITION</b></td><td><span id="positionText"></span></td> |
| 34 | </tr> |
| 35 | <tr> |
| 36 | <td><b>TRACK</b></td><td><span id="trackText"></span></td> |
| 37 | </tr> |
| 38 | <tr> |
| 39 | <td><b>ADDRESSED PLAYER</b></td><td><span id="addressedPlayerText"></span></td> |
| 40 | </tr> |
| 41 | <tr> |
| 42 | <td><b>UID COUNTER</b></td><td><span id="uidCounterText"></span></td> |
| 43 | </tr> |
| 44 | <tr> |
| 45 | <td><b>SUPPORTED EVENTS</b></td><td><span id="supportedEventsText"></span></td> |
| 46 | </tr> |
| 47 | <tr> |
| 48 | <td><b>PLAYER SETTINGS</b></td><td><div id="playerSettingsTable"></div></td> |
| 49 | </tr> |
| 50 | </table> |
| 51 | <script> |
| 52 | const portInput = document.getElementById("port") |
| 53 | const connectButton = document.getElementById("connectButton") |
| 54 | const socketState = document.getElementById("socketState") |
| 55 | const volumeText = document.getElementById("volumeText") |
| 56 | const positionText = document.getElementById("positionText") |
| 57 | const trackText = document.getElementById("trackText") |
| 58 | const playbackStatusText = document.getElementById("playbackStatusText") |
| 59 | const addressedPlayerText = document.getElementById("addressedPlayerText") |
| 60 | const uidCounterText = document.getElementById("uidCounterText") |
| 61 | const supportedEventsText = document.getElementById("supportedEventsText") |
| 62 | const playerSettingsTable = document.getElementById("playerSettingsTable") |
| 63 | const getPlayStatusResponseTable = document.getElementById("getPlayStatusResponseTable") |
| 64 | const getElementAttributesResponseTable = document.getElementById("getElementAttributesResponseTable") |
| 65 | let socket |
| 66 | let volume = 0 |
| 67 | |
| 68 | const keyNames = [ |
| 69 | "SELECT", |
| 70 | "UP", |
| 71 | "DOWN", |
| 72 | "LEFT", |
| 73 | "RIGHT", |
| 74 | "RIGHT_UP", |
| 75 | "RIGHT_DOWN", |
| 76 | "LEFT_UP", |
| 77 | "LEFT_DOWN", |
| 78 | "ROOT_MENU", |
| 79 | "SETUP_MENU", |
| 80 | "CONTENTS_MENU", |
| 81 | "FAVORITE_MENU", |
| 82 | "EXIT", |
| 83 | "NUMBER_0", |
| 84 | "NUMBER_1", |
| 85 | "NUMBER_2", |
| 86 | "NUMBER_3", |
| 87 | "NUMBER_4", |
| 88 | "NUMBER_5", |
| 89 | "NUMBER_6", |
| 90 | "NUMBER_7", |
| 91 | "NUMBER_8", |
| 92 | "NUMBER_9", |
| 93 | "DOT", |
| 94 | "ENTER", |
| 95 | "CLEAR", |
| 96 | "CHANNEL_UP", |
| 97 | "CHANNEL_DOWN", |
| 98 | "PREVIOUS_CHANNEL", |
| 99 | "SOUND_SELECT", |
| 100 | "INPUT_SELECT", |
| 101 | "DISPLAY_INFORMATION", |
| 102 | "HELP", |
| 103 | "PAGE_UP", |
| 104 | "PAGE_DOWN", |
| 105 | "POWER", |
| 106 | "VOLUME_UP", |
| 107 | "VOLUME_DOWN", |
| 108 | "MUTE", |
| 109 | "PLAY", |
| 110 | "STOP", |
| 111 | "PAUSE", |
| 112 | "RECORD", |
| 113 | "REWIND", |
| 114 | "FAST_FORWARD", |
| 115 | "EJECT", |
| 116 | "FORWARD", |
| 117 | "BACKWARD", |
| 118 | "ANGLE", |
| 119 | "SUBPICTURE", |
| 120 | "F1", |
| 121 | "F2", |
| 122 | "F3", |
| 123 | "F4", |
| 124 | "F5", |
| 125 | ] |
| 126 | |
| 127 | document.addEventListener('keydown', onKeyDown) |
| 128 | document.addEventListener('keyup', onKeyUp) |
| 129 | |
| 130 | const buttons = document.getElementById("buttons") |
| 131 | keyNames.forEach(name => { |
| 132 | const button = document.createElement("BUTTON") |
| 133 | button.appendChild(document.createTextNode(name)) |
| 134 | button.addEventListener("mousedown", event => { |
| 135 | send({type: 'send-key-down', key: name}) |
| 136 | }) |
| 137 | button.addEventListener("mouseup", event => { |
| 138 | send({type: 'send-key-up', key: name}) |
| 139 | }) |
| 140 | buttons.appendChild(button) |
| 141 | }) |
| 142 | |
| 143 | updateVolume(0) |
| 144 | |
| 145 | function connect() { |
| 146 | socket = new WebSocket(`ws://localhost:${portInput.value}`); |
| 147 | socket.onopen = _ => { |
| 148 | socketState.innerText = 'OPEN' |
| 149 | connectButton.disabled = true |
| 150 | } |
| 151 | socket.onclose = _ => { |
| 152 | socketState.innerText = 'CLOSED' |
| 153 | connectButton.disabled = false |
| 154 | } |
| 155 | socket.onerror = (error) => { |
| 156 | socketState.innerText = 'ERROR' |
| 157 | console.log(`ERROR: ${error}`) |
| 158 | connectButton.disabled = false |
| 159 | } |
| 160 | socket.onmessage = (message) => { |
| 161 | onMessage(JSON.parse(message.data)) |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | function send(message) { |
| 166 | if (socket && socket.readyState == WebSocket.OPEN) { |
| 167 | socket.send(JSON.stringify(message)) |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | function hmsText(position) { |
| 172 | const h_1 = 1000 * 60 * 60 |
| 173 | const h = Math.floor(position / h_1) |
| 174 | position -= h * h_1 |
| 175 | const m_1 = 1000 * 60 |
| 176 | const m = Math.floor(position / m_1) |
| 177 | position -= m * m_1 |
| 178 | const s_1 = 1000 |
| 179 | const s = Math.floor(position / s_1) |
| 180 | position -= s * s_1 |
| 181 | |
| 182 | return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}:${position}` |
| 183 | } |
| 184 | |
| 185 | function setTableHead(table, columns) { |
| 186 | let thead = table.createTHead() |
| 187 | let row = thead.insertRow() |
| 188 | for (let column of columns) { |
| 189 | let th = document.createElement("th") |
| 190 | let text = document.createTextNode(column) |
| 191 | th.appendChild(text) |
| 192 | row.appendChild(th) |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | function createTable(rows) { |
| 197 | const table = document.createElement("table") |
| 198 | |
| 199 | if (rows.length != 0) { |
| 200 | columns = Object.keys(rows[0]) |
| 201 | setTableHead(table, columns) |
| 202 | } |
| 203 | for (let element of rows) { |
| 204 | let row = table.insertRow() |
| 205 | for (key in element) { |
| 206 | let cell = row.insertCell() |
| 207 | let text = document.createTextNode(element[key]) |
| 208 | cell.appendChild(text) |
| 209 | } |
| 210 | } |
| 211 | return table |
| 212 | } |
| 213 | |
| 214 | function onMessage(message) { |
| 215 | console.log(message) |
| 216 | if (message.type == "set-volume") { |
| 217 | updateVolume(message.params.volume) |
| 218 | } else if (message.type == "supported-events") { |
| 219 | supportedEventsText.innerText = JSON.stringify(message.params.events) |
| 220 | } else if (message.type == "playback-position-changed") { |
| 221 | positionText.innerText = hmsText(message.params.position) |
| 222 | } else if (message.type == "playback-status-changed") { |
| 223 | playbackStatusText.innerText = message.params.status |
| 224 | } else if (message.type == "player-settings-changed") { |
| 225 | playerSettingsTable.replaceChildren(message.params.settings) |
| 226 | } else if (message.type == "track-changed") { |
| 227 | trackText.innerText = message.params.identifier |
| 228 | } else if (message.type == "addressed-player-changed") { |
| 229 | addressedPlayerText.innerText = JSON.stringify(message.params.player) |
| 230 | } else if (message.type == "uids-changed") { |
| 231 | uidCounterText.innerText = message.params.uid_counter |
| 232 | } else if (message.type == "get-play-status-response") { |
| 233 | getPlayStatusResponseTable.replaceChildren(message.params) |
| 234 | } else if (message.type == "get-element-attributes-response") { |
| 235 | getElementAttributesResponseTable.replaceChildren(createTable(message.params)) |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | function updateVolume(newVolume) { |
| 240 | volume = newVolume |
| 241 | volumeText.innerText = `${volume} (${Math.round(100*volume/0x7F)}%)` |
| 242 | } |
| 243 | |
| 244 | function onKeyDown(event) { |
| 245 | console.log(event) |
| 246 | send({ type: 'send-key-down', key: event.key }) |
| 247 | } |
| 248 | |
| 249 | function onKeyUp(event) { |
| 250 | console.log(event) |
| 251 | send({ type: 'send-key-up', key: event.key }) |
| 252 | } |
| 253 | |
| 254 | function onVolumeUpButtonClicked() { |
| 255 | updateVolume(Math.min(volume + 5, 0x7F)) |
| 256 | send({ type: 'set-volume', volume }) |
| 257 | } |
| 258 | |
| 259 | function onVolumeDownButtonClicked() { |
| 260 | updateVolume(Math.max(volume - 5, 0)) |
| 261 | send({ type: 'set-volume', volume }) |
| 262 | } |
| 263 | |
| 264 | function onGetPlayStatusButtonClicked() { |
| 265 | send({ type: 'get-play-status', volume }) |
| 266 | } |
| 267 | |
| 268 | function onGetElementAttributesButtonClicked() { |
| 269 | send({ type: 'get-element-attributes' }) |
| 270 | } |
| 271 | </script> |
| 272 | </body> |
| 273 | |
| 274 | </html> |