« get me outta code hell

implement basic share-with-party command - mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <towerofnix@gmail.com>2021-04-25 10:36:45 -0300
committer(quasar) nebula <towerofnix@gmail.com>2021-04-25 10:36:45 -0300
commitf59086b36dfa47a476320ce618ce1bf0383a6e99 (patch)
tree0b901a1e3019343290324eebdc204b1accd23dac
parent2705e786bb7c62ac644e67132ddb5bc60215b4fe (diff)
implement basic share-with-party command
-rw-r--r--socket.js81
1 files changed, 66 insertions, 15 deletions
diff --git a/socket.js b/socket.js
index d928b61..2890efb 100644
--- a/socket.js
+++ b/socket.js
@@ -51,6 +51,41 @@ const {
   isGroup
 } = require('./playlist-utils')
 
+function serializePartySource(item) {
+  // Turn an item into a sanitized, compact format for sharing with the server
+  // and other sockets in the party.
+  //
+  // TODO: We'll probably need to assign a unique ID to the root item, since
+  // otherwise we don't have a way to target it to un-share it.
+
+  if (isGroup(item)) {
+    return [item.name, ...item.items.map(serializePartySource).filter(Boolean)]
+  } else if (isTrack(item)) {
+    return item.name
+  } else {
+    return null
+  }
+}
+
+function deserializePartySource(source) {
+  // Reconstruct a party source into the ordinary group/track format.
+
+  const recursive = source => {
+    if (Array.isArray(source)) {
+      return {name: source[0], items: source.slice(1).map(recursive).filter(Boolean)}
+    } else if (typeof source === 'string') {
+      return {name: source, downloaderArg: '-'}
+    } else {
+      return null
+    }
+  }
+
+  const top = recursive(source)
+  return (isGroup(top)
+    ? updateGroupFormat(top)
+    : updateTrackFormat(top))
+}
+
 function serializeCommandToData(command) {
   // Turn a command into a string/buffer that can be sent over a socket.
   return JSON.stringify(command)
@@ -192,6 +227,11 @@ function validateCommand(command) {
               command.sender === 'server'
             ) || !command.startingTrack
           )
+        case 'share-with-party':
+          return (
+            typeof command.item === 'string' ||
+            Array.isArray(command.item)
+          )
         case 'status':
           return (
             command.status === 'done-playing' ||
@@ -535,6 +575,12 @@ function attachBackendToSocketClient(backend, client, {
           actionmsg = 'shuffled the queue'
         }
         break
+      case 'share-with-party':
+        // TODO: This isn't an outrageously expensive operation, but it still
+        // seems a little unnecessary to deserialize it here if we also do that
+        // when actually processing the source?
+        actionmsg = `shared ${itemToMessage(deserializePartySource(command.item))} with the party`
+        break
       case 'seek-to':
         // TODO: the second value here should be the duration of the track
         // (this will make values like 0:0x:yy / 1:xx:yy appear correctly)
@@ -709,6 +755,14 @@ function attachBackendToSocketClient(backend, client, {
             }, command.startingTrack ? 500 : 0)
             return
           }
+          case 'share-with-party': {
+            const deserialized = deserializePartySource(command.item)
+            const partyGrouplike = partyGrouplikeMap[command.senderSocketId]
+            deserialized[parentSymbol] = partyGrouplike
+            partyGrouplike.items.push(deserialized)
+            backend.partyGrouplikeUpdated(command.senderSocketId, partyGrouplike)
+            return
+          }
           case 'stop-playing':
             if (QP) silenceEvents(QP, ['playing'], () => QP.stopPlaying())
             return
@@ -844,24 +898,21 @@ function attachBackendToSocketClient(backend, client, {
     })
   })
 
-  backend.on('share with party', origItem => {
-    let newItem = {
-      ...origItem,
-      [parentSymbol]: partyGrouplike,
-      [originalSymbol]: origItem
-    }
+  backend.on('share with party', item => {
+    if (partyGrouplike.items.every(x => x[originalSymbol] !== item)) {
+      const serialized = serializePartySource(item)
+      const deserialized = deserializePartySource(serialized)
 
-    if (isGroup(newItem)) {
-      newItem = updateGroupFormat(newItem)
-    } else if (isTrack(newItem)) {
-      newItem = updateTrackFormat(newItem)
-    } else {
-      return
-    }
+      deserialized[parentSymbol] = partyGrouplike
+      deserialized[originalSymbol] = item
 
-    if (partyGrouplike.items.every(x => x[originalSymbol] !== origItem)) {
-      partyGrouplike.items.push(newItem)
+      partyGrouplike.items.push(deserialized)
       backend.partyGrouplikeUpdated(client.socketId, partyGrouplike)
+
+      client.sendCommand({
+        code: 'share-with-party',
+        item: serialized
+      })
     }
   })
 }