DabDaddy6223

jukebox_backend_main

Jun 20th, 2026 (edited)
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.36 KB | None | 0 0
  1. -- API --------------------------------------------------
  2.  
  3. local w, h = term.getSize()
  4.  
  5. function printCentered(y, str)
  6.    local x = math.floor((w - string.len(str)) / 2)
  7.    term.setCursorPos(x, y)
  8.    term.clearLine()
  9.    term.write(str)
  10. end
  11.  
  12. function printThird(y, third, str)
  13.     local third_width = w / 3
  14.  
  15.     -- Centre position of the requested third
  16.     local centre_x = (third - 0.5) * third_width
  17.  
  18.     local x = math.floor(centre_x - (#str / 2))
  19.  
  20.     term.setCursorPos(x, y)
  21.     term.write(str)
  22. end
  23.  
  24. function hasValue (tab, val)
  25.     for index, value in ipairs(tab) do
  26.         if value == val then
  27.             return true
  28.         end
  29.     end
  30.  
  31.     return false
  32. end
  33.  
  34. function printKeys(tab)
  35.     -- Source - https://stackoverflow.com/a/12674376
  36.     -- Posted by lhf
  37.     -- Retrieved 2026-06-11, License - CC BY-SA 3.0
  38.  
  39.     local keyset={}
  40.     local n=0
  41.  
  42.     for k,v in pairs(tab) do
  43.         n=n+1
  44.         keyset[n]=k
  45.     end
  46.  
  47.     print(textutils.serialise(keyset))
  48. end
  49.  
  50. ---------------------------------------------------------
  51.  
  52. JUKEBOX_ID = 1
  53.  
  54. local dfpwm = require("cc.audio.dfpwm")
  55. local speaker
  56. local decoder
  57. local connected_jukebox_frontend
  58.  
  59. local protocol
  60.  
  61. local skip_requested = false
  62. local songs = {}
  63. local state = {
  64.     current_song = nil,
  65.     queue = {}
  66. }
  67.  
  68. function playSoundFromUrl(url)
  69.     local response, err = http.get(url)
  70.  
  71.     if not response then
  72.         print("Failed to fetch audio:")
  73.         print(err)
  74.         return
  75.     end
  76.  
  77.     while true do
  78.         if skip_requested then
  79.             skip_requested = false
  80.             response.close()
  81.             return
  82.         end
  83.  
  84.         local chunk = response.read(16 * 1024)
  85.  
  86.         if not chunk then
  87.             break
  88.         end
  89.  
  90.         local buffer = decoder(chunk)
  91.  
  92.         while not speaker.playAudio(buffer) do
  93.             os.pullEvent("speaker_audio_empty")
  94.  
  95.             if skip_requested then
  96.                 skip_requested = false
  97.                 response.close()
  98.                 return
  99.             end
  100.         end
  101.     end
  102.  
  103.     response.close()
  104. end
  105.  
  106. function playSong(song_id)
  107.     local song = songs[song_id]
  108.  
  109.     if not song then
  110.         print("Unknown song: " .. tostring(song_id))
  111.         return
  112.     end
  113.  
  114.     local url =
  115.         "https://raw.githubusercontent.com/dabusmc/jukebox_data/refs/heads/main/sounds/"
  116.         .. song["file_name"]
  117.  
  118.     print("Streaming: " .. song["display_name"])
  119.  
  120.     playSoundFromUrl(url)
  121. end
  122.  
  123. local function sendQueueUpdate()
  124.     rednet.send(connected_jukebox_frontend, {
  125.         type = "queue_update",
  126.         current_song = state.current_song,
  127.         queue = state.queue
  128.     }, protocol)
  129. end
  130.  
  131. local function playbackLoop()
  132.     while true do
  133.         if state.current_song == nil and #state.queue > 0 then
  134.             state.current_song = table.remove(state.queue, 1)
  135.             sendQueueUpdate()
  136.  
  137.             playSong(state.current_song)
  138.  
  139.             state.current_song = nil
  140.             sendQueueUpdate()
  141.         end
  142.  
  143.         sleep(0.1)
  144.     end
  145. end
  146.  
  147. local function networkLoop()
  148.     while true do
  149.  
  150.         local id, message, received_protocol = rednet.receive()
  151.  
  152.         if received_protocol == protocol then
  153.             if message.action == "queue" then
  154.                 table.insert(state.queue, message.song_id)
  155.                 sendQueueUpdate()
  156.             elseif message.action == "skip" then
  157.                 skip_requested = true
  158.             elseif message.action == "get_state" then
  159.                 rednet.send(id, {
  160.                     type = "queue_update",
  161.                     current_song = state.current_song,
  162.                     queue = state.queue
  163.                 }, protocol)
  164.             end
  165.         end
  166.     end
  167. end
  168.  
  169. local function gatherSongData()
  170.     local song_list = fs.find("songs/*/*.json")
  171.     for _, song_path in ipairs(song_list) do
  172.         -- Decode data
  173.         local song_file = fs.open(song_path, "r")
  174.         local song_contents = song_file.readAll()
  175.         song_file.close()
  176.  
  177.         local song_data = textutils.unserializeJSON(song_contents)
  178.         local song_key = song_path
  179.         if string.find(song_key, "songs/") ~= nil then
  180.             song_key = string.sub(song_key, 7, #song_key - 5)
  181.         end
  182.         songs[song_key] = song_data
  183.     end
  184. end
  185.  
  186. function main()
  187.     gatherSongData()
  188.     speaker = peripheral.find("speaker")
  189.     decoder = dfpwm.make_decoder()
  190.  
  191.     peripheral.find("modem", rednet.open)
  192.  
  193.     protocol = "jukebox_" .. tostring(JUKEBOX_ID)
  194.     rednet.broadcast("ping", protocol)
  195.  
  196.     local timer_id = os.startTimer(1)
  197.  
  198.     connected_jukebox_frontend = nil
  199.     repeat
  200.         local event, p1, p2, p3 = os.pullEvent()
  201.  
  202.         if event == "rednet_message" then
  203.             local id = p1
  204.             local message = p2
  205.             local received_protocol = p3
  206.  
  207.             if received_protocol == protocol then
  208.                 if message == "pong" then
  209.                     connected_jukebox_frontend = id
  210.                 end
  211.             end
  212.         elseif event == "timer" and p1 == timer_id then
  213.             rednet.broadcast("ping", protocol)
  214.             timer_id = os.startTimer(1)
  215.         end
  216.     until connected_jukebox_frontend ~= nil
  217.  
  218.     print("Connected to Computer #" .. tostring(connected_jukebox_frontend))
  219.  
  220.     parallel.waitForAny(
  221.         playbackLoop,
  222.         networkLoop
  223.     )
  224. end
  225.  
  226. main()
Advertisement
Add Comment
Please, Sign In to add comment