DabDaddy6223

jukebox_frontend_queue

Jun 19th, 2026 (edited)
39
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.29 KB | None | 0 0
  1. -- API --------------------------------------------------
  2.  
  3. os.pullEvent = os.pullEventRaw
  4.  
  5. local w, h = term.getSize()
  6.  
  7. function printCentered(y, str)
  8.    local x = math.floor((w - string.len(str)) / 2)
  9.    term.setCursorPos(x, y)
  10.    term.clearLine()
  11.    term.write(str)
  12. end
  13.  
  14. function printThird(y, third, str)
  15.     local third_width = w / 3
  16.  
  17.     -- Centre position of the requested third
  18.     local centre_x = (third - 0.5) * third_width
  19.  
  20.     local x = math.floor(centre_x - (#str / 2))
  21.  
  22.     term.setCursorPos(x, y)
  23.     term.write(str)
  24. end
  25.  
  26. function hasValue (tab, val)
  27.     for index, value in ipairs(tab) do
  28.         if value == val then
  29.             return true
  30.         end
  31.     end
  32.  
  33.     return false
  34. end
  35.  
  36. function printKeys(tab)
  37.     -- Source - https://stackoverflow.com/a/12674376
  38.     -- Posted by lhf
  39.     -- Retrieved 2026-06-11, License - CC BY-SA 3.0
  40.  
  41.     local keyset={}
  42.     local n=0
  43.  
  44.     for k,v in pairs(tab) do
  45.         n=n+1
  46.         keyset[n]=k
  47.     end
  48.  
  49.     print(textutils.serialise(keyset))
  50. end
  51.  
  52. ---------------------------------------------------------
  53.  
  54. local jukebox_id, jukebox_backend_id = ...
  55.  
  56. JUKEBOX_ID = tonumber(jukebox_id)
  57. JUKEBOX_BACKEND_ID = tonumber(jukebox_backend_id)
  58.  
  59. local protocol = "jukebox_" .. tostring(JUKEBOX_ID)
  60.  
  61. local queue = {}
  62. local songs = {}
  63. local songs_by_id = {}
  64. local current_song = nil
  65.  
  66. local queue_scroll = 0
  67. local visible_items = h - 6
  68.  
  69. local menu_option = 1
  70. local song_selection = 1
  71.  
  72. local function printSongCenteredOnDash(y, song)
  73.     local title, artist = song:match("^(.-)%s%-%s(.+)$")
  74.  
  75.     if not title then
  76.         printCentered(y, song)
  77.         return
  78.     end
  79.  
  80.     local centre_x = math.floor(w / 2)
  81.  
  82.     -- Print title so it ends just before the dash
  83.     term.setCursorPos(centre_x - #title - 1, y)
  84.     term.write(title)
  85.  
  86.     -- Print dash
  87.     term.setCursorPos(centre_x, y)
  88.     term.write("-")
  89.  
  90.     -- Print artist
  91.     term.setCursorPos(centre_x + 2, y)
  92.     term.write(artist)
  93. end
  94.  
  95. local function drawMenu()
  96.     term.clear()
  97.     term.setCursorPos(1, 1)
  98.     term.write("Jukebox OS Alpha //")
  99.  
  100.     term.setCursorPos(w - 4, 1)
  101.     if menu_option == 1 then
  102.         term.write("Add")
  103.     elseif menu_option == 2 then
  104.         term.write("Skip")
  105.     elseif menu_option == 3 then
  106.         term.write("Exit")
  107.     elseif menu_option == 4 then
  108.         term.write("Ok")
  109.     end
  110. end
  111.  
  112. local function drawFrontend()
  113.     printCentered(2, " Queue")
  114.    
  115.     local now_playing_text = "Nothing Playing"
  116.  
  117.     if current_song then
  118.         local song = songs_by_id[current_song]
  119.  
  120.         if song then
  121.             now_playing_text =
  122.                 "Now Playing: " .. song["display_name"] .. " - " .. song["artist"]
  123.         end
  124.     end
  125.  
  126.     printCentered(3, now_playing_text)
  127.  
  128.     for screen_row = 1, visible_items do
  129.         local queue_index = queue_scroll + screen_row
  130.  
  131.         if queue_index > #queue then
  132.             break
  133.         end
  134.  
  135.         local song_id = queue[queue_index]
  136.         local song = songs_by_id[song_id]
  137.  
  138.         local song_display_name
  139.         if song then
  140.             song_display_name = song["display_name"] .. " - " .. song["artist"]
  141.         else
  142.             song_display_name = song_id
  143.         end
  144.  
  145.         printSongCenteredOnDash(
  146.             3 + screen_row,
  147.             song_display_name
  148.         )
  149.     end
  150.  
  151.     printThird(h - 1, 1, ((menu_option == 1) and "[ Add ]") or "Add")
  152.     printThird(h - 1, 2, ((menu_option == 2) and "[ Skip ]") or "Skip")
  153.     printThird(h - 1, 3, ((menu_option == 3) and "[ Exit ]") or "Exit")
  154. end
  155.  
  156. local function displaySkipPopup()
  157.     term.clear()
  158.  
  159.     menu_option = 4
  160.     drawMenu()
  161.  
  162.     printCentered(math.floor(h/2) + 1, "Nothing to skip.")
  163.     printCentered(math.floor(h/2) + 3, "[ Ok ]")
  164.  
  165.     while true do
  166.         local e, p = os.pullEvent()
  167.         if e == "key" then
  168.             local key = p
  169.             if key == keys.enter then
  170.                 break
  171.             end
  172.         end
  173.     end
  174. end
  175.  
  176. local function skipCurrentQueueItem()
  177.     if current_song == nil and #queue == 0 then
  178.         -- We can't skip because there's nothing to skip
  179.         displaySkipPopup()
  180.         menu_option = 2
  181.         return
  182.     end
  183.  
  184.     rednet.send(
  185.         JUKEBOX_BACKEND_ID,
  186.         {
  187.             action = "skip"
  188.         },
  189.         protocol
  190.     )
  191. end
  192.  
  193. local function networkLoop()
  194.     while true do
  195.         local id, message = rednet.receive(protocol)
  196.  
  197.         if type(message) == "table" and message.type == "queue_update" then
  198.             queue = message.queue
  199.             current_song = message.current_song
  200.  
  201.             drawMenu()
  202.             drawFrontend()
  203.         end
  204.     end
  205. end
  206.  
  207. local function drawSongs()
  208.     printCentered(3, "Add Song")
  209.  
  210.     for i, song in ipairs(songs) do
  211.         local song_name = song["display_name"] .. " - " .. song["artist"]
  212.  
  213.         if song_selection == i then
  214.             song_name = "[ " .. song_name .. " ]"
  215.         end
  216.  
  217.         printSongCenteredOnDash(3 + i, song_name)
  218.     end
  219.  
  220.     printCentered(h - 1, ((song_selection == #songs + 1) and "[ Back ]") or "Back")
  221. end
  222.  
  223. local displayQueueArea
  224.  
  225. local function displayAddSongArea()
  226.     song_selection = 1
  227.     drawMenu()
  228.     drawSongs()
  229.  
  230.     while true do
  231.         local e, p = os.pullEvent()
  232.         if e == "key" then
  233.             local key = p
  234.             if key == keys.w or key == keys.up then
  235.                 if song_selection > 1 then
  236.                     song_selection = song_selection - 1
  237.                     drawMenu()
  238.                     drawSongs()
  239.                 end
  240.             elseif key == keys.s or key == keys.down then
  241.                 if song_selection < #songs + 1 then
  242.                     song_selection = song_selection + 1
  243.                     drawMenu()
  244.                     drawSongs()
  245.                 end
  246.             elseif key == keys.enter then
  247.                 break
  248.             end
  249.         end
  250.     end
  251.  
  252.     if song_selection <= #songs then
  253.         local song = songs[song_selection]
  254.  
  255.         local display_name = song["display_name"] .. " - " .. song["artist"]
  256.         rednet.send(
  257.             JUKEBOX_BACKEND_ID,
  258.             {
  259.                 action = "queue",
  260.                 song_id = song.id
  261.             },
  262.             protocol
  263.         )
  264.  
  265.         queue_scroll = math.max(0, #queue - visible_items)
  266.     end
  267.  
  268.     displayQueueArea()
  269. end
  270.  
  271. displayQueueArea = function()
  272.     rednet.send(
  273.         JUKEBOX_BACKEND_ID,
  274.         {
  275.             action = "get_state"
  276.         },
  277.         protocol
  278.     )
  279.  
  280.     drawMenu()
  281.     drawFrontend()
  282.  
  283.     while true do
  284.         local e, p = os.pullEvent()
  285.         if e == "key" then
  286.             local key = p
  287.             if key == keys.w or key == keys.up then
  288.                 if queue_scroll > 0 then
  289.                     queue_scroll = queue_scroll - 1
  290.                     drawMenu()
  291.                     drawFrontend()
  292.                 end
  293.  
  294.             elseif key == keys.s or key == keys.down then
  295.                 local visible_items = h - 5
  296.  
  297.                 if queue_scroll < math.max(0, #queue - visible_items) then
  298.                     queue_scroll = queue_scroll + 1
  299.                     drawMenu()
  300.                     drawFrontend()
  301.                 end
  302.             elseif key == keys.a or key == keys.left then
  303.                 if menu_option > 1 then
  304.                     menu_option = menu_option - 1
  305.                     drawMenu()
  306.                     drawFrontend()
  307.                 end
  308.             elseif key == keys.d or key == keys.right then
  309.                 if menu_option < 3 then
  310.                     menu_option = menu_option + 1
  311.                     drawMenu()
  312.                     drawFrontend()
  313.                 end
  314.             elseif key == keys.enter then
  315.                 break
  316.             end
  317.         end
  318.     end
  319.  
  320.     term.clear()
  321.  
  322.     if menu_option == 1 then
  323.         displayAddSongArea()
  324.     elseif menu_option == 2 then
  325.         skipCurrentQueueItem()
  326.         term.clear()
  327.         displayQueueArea()
  328.     elseif menu_option == 3 then
  329.         shell.run("jukebox_frontend", JUKEBOX_ID, JUKEBOX_BACKEND_ID)
  330.     end
  331. end
  332.  
  333. local function gatherSongData()
  334.     local song_list = fs.find("songs/*/*.json")
  335.     for _, song_path in ipairs(song_list) do
  336.         -- Decode data
  337.         local song_file = fs.open(song_path, "r")
  338.         local song_contents = song_file.readAll()
  339.         song_file.close()
  340.  
  341.         local song_data = textutils.unserializeJSON(song_contents)
  342.  
  343.         local song_key = song_path
  344.         if string.find(song_key, "songs/") ~= nil then
  345.             song_key = string.sub(song_key, 7, #song_key - 5)
  346.         end
  347.  
  348.         song_data["id"] = song_key
  349.        
  350.         -- Add to songs list
  351.         songs_by_id[song_key] = song_data
  352.         songs[#songs + 1] = song_data
  353.     end
  354. end
  355.  
  356. function main()
  357.     rednet.send(
  358.         JUKEBOX_BACKEND_ID,
  359.         {
  360.             action = "get_state"
  361.         },
  362.         protocol
  363.     )
  364.  
  365.     while true do
  366.         local id, message = rednet.receive(protocol)
  367.  
  368.         if message.type == "queue_update" then
  369.             queue = message.queue
  370.             current_song = message.current_song
  371.             break
  372.         end
  373.  
  374.         sleep(0.1)
  375.     end
  376.  
  377.     gatherSongData()
  378.    
  379.     parallel.waitForAny(
  380.         displayQueueArea,
  381.         networkLoop
  382.     )
  383. end
  384.  
  385. main()
Advertisement
Add Comment
Please, Sign In to add comment