robathome

MC_jukebox - Remote

Oct 27th, 2025 (edited)
660
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.64 KB | None | 0 0
  1. -- pocket_compact_controller.txt
  2. -- Compact controller UI for Advanced Wireless Pocket Computer.
  3. -- Requires server to include server_cmd_patch.txt and to run
  4. -- mirrorHelloLoop + mirrorStatusLoop.
  5.  
  6. local MODE = "ui-mirror-v1"
  7.  
  8. -- Open rednet
  9. local function _openRednetClient()
  10. local side = nil
  11. for _, s in ipairs(rs.getSides()) do
  12. if peripheral.getType(s) == "modem" then side = s break end
  13. end
  14. assert(side, "Wireless modem required on client")
  15. if not rednet.isOpen(side) then rednet.open(side) end
  16. return side
  17. end
  18. _openRednetClient()
  19.  
  20. -- State mirrored from server
  21. local S = {
  22. now = nil, playing = false, looping = 0, volume = 1.0,
  23. is_loading = false, is_error = false, queue = {}, last_search = nil,
  24. search_results = nil,
  25. }
  26.  
  27. local cw, ch = term.getSize()
  28. local TAB = 1 -- 1=Now, 2=Queue, 3=Find
  29. local selIdx = 1 -- selection index for lists
  30. local resIdx = 1 -- selection for search results
  31. local serverId = nil
  32.  
  33. -- Helpers
  34. local function send(pkt)
  35. if serverId then rednet.send(serverId, pkt, MODE) else rednet.broadcast(pkt, MODE) end
  36. end
  37.  
  38. local function cmd(name, extra)
  39. local m = { op="CMD", cmd=name }
  40. if extra then for k,v in pairs(extra) do m[k]=v end end
  41. send(m)
  42. end
  43.  
  44. -- UI draw
  45. local function bar(t) term.setBackgroundColor(colors.gray) term.setTextColor(colors.white) term.setCursorPos(1,1) term.clearLine() term.write(t) end
  46. local function footer(t) term.setCursorPos(1,ch) term.setBackgroundColor(colors.gray) term.setTextColor(colors.white) term.clearLine() term.write(t) end
  47. local function clearBody() term.setBackgroundColor(colors.black) for y=2,ch-1 do term.setCursorPos(1,y) term.clearLine() end end
  48.  
  49. local function drawNow()
  50. bar(" Now | Queue | Find ")
  51. clearBody()
  52. term.setTextColor(colors.white)
  53. term.setCursorPos(2,3)
  54. term.write(S.now and (S.now.name or "Unknown") or "Not playing")
  55. term.setCursorPos(2,4)
  56. term.setTextColor(colors.lightGray)
  57. term.write(S.now and (S.now.artist or "") or "")
  58.  
  59. term.setTextColor(colors.white)
  60. term.setCursorPos(2,6)
  61. local status = (S.is_error and "Error") or (S.is_loading and "Loading") or (S.playing and "Playing") or "Stopped"
  62. term.write(("Status: %s"):format(status))
  63.  
  64. -- Volume line
  65. local pct = math.floor((S.volume/3)*100 + 0.5)
  66. term.setCursorPos(2,8); term.write(("Vol: %3d%%"):format(pct))
  67.  
  68. -- Loop state
  69. local loopTxt = (S.looping==0 and "Off") or (S.looping==1 and "Queue") or "Song"
  70. term.setCursorPos(2,9); term.write("Loop: "..loopTxt)
  71.  
  72. footer("⏯ Play/Pause ⏭ Skip L Loop - Vol+ + Vol- 2 Queue 3 Find")
  73. end
  74.  
  75. local function drawQueue()
  76. bar(" Now |*Queue*| Find ")
  77. clearBody()
  78. term.setTextColor(colors.white)
  79. term.setCursorPos(2,2) term.write("Up Next:")
  80. for i=1, math.min(#S.queue, ch-5) do
  81. local y = 2 + i
  82. term.setCursorPos(2,y)
  83. if i==selIdx then term.setBackgroundColor(colors.white) term.setTextColor(colors.black) else term.setBackgroundColor(colors.black) term.setTextColor(colors.white) end
  84. local name = S.queue[i].name or "Unknown"
  85. term.write(name:sub(1, cw-2))
  86. term.setBackgroundColor(colors.black) term.setTextColor(colors.lightGray)
  87. term.setCursorPos(2,y+1)
  88. if S.queue[i].artist then term.write(("by %s"):format(S.queue[i].artist):sub(1, cw-2)) end
  89. y = y + 1
  90. end
  91. footer("↑/↓ Select Enter Play D Delete 1 Now 3 Find")
  92. end
  93.  
  94. local function drawFind()
  95. bar(" Now | Queue |*Find*")
  96. clearBody()
  97. term.setCursorPos(2,2) term.setTextColor(colors.white) term.write("Query:")
  98. term.setCursorPos(2,3) term.setTextColor(colors.yellow)
  99. term.write(S.last_search or "(press S to set)")
  100.  
  101. term.setTextColor(colors.white)
  102. term.setCursorPos(2,5) term.write("Results:")
  103. local list = S.search_results or {}
  104. for i=1, math.min(#list, ch-8) do
  105. local y = 5 + i
  106. term.setCursorPos(2,y)
  107. if i==resIdx then term.setBackgroundColor(colors.white) term.setTextColor(colors.black) else term.setBackgroundColor(colors.black) term.setTextColor(colors.white) end
  108. local name = list[i].name or "Unknown"
  109. term.write(name:sub(1, cw-2))
  110. term.setBackgroundColor(colors.black) term.setTextColor(colors.lightGray)
  111. term.setCursorPos(2,y+1)
  112. if list[i].artist then term.write(("by %s"):format(list[i].artist):sub(1, cw-2)) end
  113. end
  114. footer("S Search Enter Play N PlayNext A Add 1 Now 2 Queue")
  115. end
  116.  
  117. local function redraw()
  118. term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1,1)
  119. if TAB==1 then drawNow()
  120. elseif TAB==2 then drawQueue()
  121. else drawFind() end
  122. end
  123.  
  124. -- Net receive
  125. local function netLoop()
  126. while true do
  127. local id, msg, proto = rednet.receive(MODE)
  128. if proto == MODE and type(msg) == "table" then
  129. if msg.op == "HELLO_ACK" then
  130. serverId = id
  131. elseif msg.op == "STATUS" then
  132. serverId = serverId or id
  133. S.now = msg.now; S.playing = msg.playing; S.looping = msg.looping
  134. S.volume = msg.volume; S.is_loading = msg.is_loading; S.is_error = msg.is_error
  135. S.queue = msg.queue or {}; S.last_search = msg.last_search; S.search_results = msg.search_results
  136. redraw()
  137. elseif msg.op == "screen" then
  138. serverId = serverId or id
  139. end
  140. end
  141. end
  142. end
  143.  
  144. -- Periodic hello + status requests
  145. local function helloLoop()
  146. while true do
  147. if not serverId then rednet.broadcast({ op="HELLO", w=cw, h=ch }, MODE) end
  148. send({ op="STATUS_REQ" })
  149. sleep(1.0)
  150. end
  151. end
  152.  
  153. -- Input
  154. local function inputLoop()
  155. redraw()
  156. while true do
  157. local e, p1, p2, p3 = os.pullEvent()
  158. if e == "key" then
  159. local k = p1
  160. if k == keys.one then TAB=1; redraw()
  161. elseif k == keys.two then TAB=2; redraw()
  162. elseif k == keys.three then TAB=3; redraw()
  163. elseif TAB == 1 then
  164. if k == keys.space then cmd("PLAY_TOGGLE")
  165. elseif k == keys.l then cmd("LOOP_NEXT")
  166. elseif k == keys.minus then cmd("VOL_SET", {value = math.max(0, (S.volume or 1)-0.15)})
  167. elseif k == keys.equals or k == keys.plus then cmd("VOL_SET", {value = math.min(3, (S.volume or 1)+0.15)})
  168. elseif k == keys.right then cmd("SKIP")
  169. end
  170. elseif TAB == 2 then
  171. if k == keys.up then selIdx = math.max(1, selIdx-1); redraw()
  172. elseif k == keys.down then selIdx = math.min(math.max(#S.queue,1), selIdx+1); redraw()
  173. elseif k == keys.enter then cmd("PLAY_FROM_QUEUE_IDX", {idx = selIdx})
  174. elseif k == keys.d then cmd("REMOVE_QUEUE_IDX", {idx = selIdx})
  175. end
  176. elseif TAB == 3 then
  177. if k == keys.up then resIdx = math.max(1, resIdx-1); redraw()
  178. elseif k == keys.down then resIdx = math.min(math.max(#(S.search_results or {}),1), resIdx+1); redraw()
  179. elseif k == keys.s then
  180. term.setCursorBlink(true)
  181. term.setCursorPos(2,3)
  182. term.setTextColor(colors.white) term.setBackgroundColor(colors.black)
  183. term.clearLine() term.setCursorPos(2,3)
  184. local q = read()
  185. term.setCursorBlink(false)
  186. if q and #q>0 then cmd("SEARCH", {q=q}) end
  187. elseif k == keys.enter then cmd("PLAY_NOW", {idx = resIdx})
  188. elseif k == keys.n then cmd("PLAY_NEXT", {idx = resIdx})
  189. elseif k == keys.a then cmd("ADD_QUEUE", {idx = resIdx})
  190. end
  191. end
  192. elseif e == "mouse_click" then
  193. local x,y = p2,p3
  194. -- Top bar tabs by rough regions
  195. if y == 1 then
  196. if x <= 8 then TAB=1 elseif x <= 16 then TAB=2 else TAB=3 end
  197. redraw()
  198. end
  199. end
  200. end
  201. end
  202.  
  203. -- Start
  204. term.setBackgroundColor(colors.black) term.clear() term.setCursorPos(1,1)
  205. print("Pocket controller")
  206. parallel.waitForAny(helloLoop, netLoop, inputLoop)
  207.  
Advertisement
Add Comment
Please, Sign In to add comment