Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- API --------------------------------------------------
- os.pullEvent = os.pullEventRaw
- local w, h = term.getSize()
- function printCentered(y, str)
- local x = math.floor((w - string.len(str)) / 2)
- term.setCursorPos(x, y)
- term.clearLine()
- term.write(str)
- end
- function printThird(y, third, str)
- local third_width = w / 3
- -- Centre position of the requested third
- local centre_x = (third - 0.5) * third_width
- local x = math.floor(centre_x - (#str / 2))
- term.setCursorPos(x, y)
- term.write(str)
- end
- function hasValue (tab, val)
- for index, value in ipairs(tab) do
- if value == val then
- return true
- end
- end
- return false
- end
- function printKeys(tab)
- -- Source - https://stackoverflow.com/a/12674376
- -- Posted by lhf
- -- Retrieved 2026-06-11, License - CC BY-SA 3.0
- local keyset={}
- local n=0
- for k,v in pairs(tab) do
- n=n+1
- keyset[n]=k
- end
- print(textutils.serialise(keyset))
- end
- ---------------------------------------------------------
- local jukebox_id, jukebox_backend_id = ...
- JUKEBOX_ID = tonumber(jukebox_id)
- JUKEBOX_BACKEND_ID = tonumber(jukebox_backend_id)
- local protocol = "jukebox_" .. tostring(JUKEBOX_ID)
- local queue = {}
- local songs = {}
- local songs_by_id = {}
- local current_song = nil
- local queue_scroll = 0
- local visible_items = h - 6
- local menu_option = 1
- local song_selection = 1
- local function printSongCenteredOnDash(y, song)
- local title, artist = song:match("^(.-)%s%-%s(.+)$")
- if not title then
- printCentered(y, song)
- return
- end
- local centre_x = math.floor(w / 2)
- -- Print title so it ends just before the dash
- term.setCursorPos(centre_x - #title - 1, y)
- term.write(title)
- -- Print dash
- term.setCursorPos(centre_x, y)
- term.write("-")
- -- Print artist
- term.setCursorPos(centre_x + 2, y)
- term.write(artist)
- end
- local function drawMenu()
- term.clear()
- term.setCursorPos(1, 1)
- term.write("Jukebox OS Alpha //")
- term.setCursorPos(w - 4, 1)
- if menu_option == 1 then
- term.write("Add")
- elseif menu_option == 2 then
- term.write("Skip")
- elseif menu_option == 3 then
- term.write("Exit")
- elseif menu_option == 4 then
- term.write("Ok")
- end
- end
- local function drawFrontend()
- printCentered(2, " Queue")
- local now_playing_text = "Nothing Playing"
- if current_song then
- local song = songs_by_id[current_song]
- if song then
- now_playing_text =
- "Now Playing: " .. song["display_name"] .. " - " .. song["artist"]
- end
- end
- printCentered(3, now_playing_text)
- for screen_row = 1, visible_items do
- local queue_index = queue_scroll + screen_row
- if queue_index > #queue then
- break
- end
- local song_id = queue[queue_index]
- local song = songs_by_id[song_id]
- local song_display_name
- if song then
- song_display_name = song["display_name"] .. " - " .. song["artist"]
- else
- song_display_name = song_id
- end
- printSongCenteredOnDash(
- 3 + screen_row,
- song_display_name
- )
- end
- printThird(h - 1, 1, ((menu_option == 1) and "[ Add ]") or "Add")
- printThird(h - 1, 2, ((menu_option == 2) and "[ Skip ]") or "Skip")
- printThird(h - 1, 3, ((menu_option == 3) and "[ Exit ]") or "Exit")
- end
- local function displaySkipPopup()
- term.clear()
- menu_option = 4
- drawMenu()
- printCentered(math.floor(h/2) + 1, "Nothing to skip.")
- printCentered(math.floor(h/2) + 3, "[ Ok ]")
- while true do
- local e, p = os.pullEvent()
- if e == "key" then
- local key = p
- if key == keys.enter then
- break
- end
- end
- end
- end
- local function skipCurrentQueueItem()
- if current_song == nil and #queue == 0 then
- -- We can't skip because there's nothing to skip
- displaySkipPopup()
- menu_option = 2
- return
- end
- rednet.send(
- JUKEBOX_BACKEND_ID,
- {
- action = "skip"
- },
- protocol
- )
- end
- local function networkLoop()
- while true do
- local id, message = rednet.receive(protocol)
- if type(message) == "table" and message.type == "queue_update" then
- queue = message.queue
- current_song = message.current_song
- drawMenu()
- drawFrontend()
- end
- end
- end
- local function drawSongs()
- printCentered(3, "Add Song")
- for i, song in ipairs(songs) do
- local song_name = song["display_name"] .. " - " .. song["artist"]
- if song_selection == i then
- song_name = "[ " .. song_name .. " ]"
- end
- printSongCenteredOnDash(3 + i, song_name)
- end
- printCentered(h - 1, ((song_selection == #songs + 1) and "[ Back ]") or "Back")
- end
- local displayQueueArea
- local function displayAddSongArea()
- song_selection = 1
- drawMenu()
- drawSongs()
- while true do
- local e, p = os.pullEvent()
- if e == "key" then
- local key = p
- if key == keys.w or key == keys.up then
- if song_selection > 1 then
- song_selection = song_selection - 1
- drawMenu()
- drawSongs()
- end
- elseif key == keys.s or key == keys.down then
- if song_selection < #songs + 1 then
- song_selection = song_selection + 1
- drawMenu()
- drawSongs()
- end
- elseif key == keys.enter then
- break
- end
- end
- end
- if song_selection <= #songs then
- local song = songs[song_selection]
- local display_name = song["display_name"] .. " - " .. song["artist"]
- rednet.send(
- JUKEBOX_BACKEND_ID,
- {
- action = "queue",
- song_id = song.id
- },
- protocol
- )
- queue_scroll = math.max(0, #queue - visible_items)
- end
- displayQueueArea()
- end
- displayQueueArea = function()
- rednet.send(
- JUKEBOX_BACKEND_ID,
- {
- action = "get_state"
- },
- protocol
- )
- drawMenu()
- drawFrontend()
- while true do
- local e, p = os.pullEvent()
- if e == "key" then
- local key = p
- if key == keys.w or key == keys.up then
- if queue_scroll > 0 then
- queue_scroll = queue_scroll - 1
- drawMenu()
- drawFrontend()
- end
- elseif key == keys.s or key == keys.down then
- local visible_items = h - 5
- if queue_scroll < math.max(0, #queue - visible_items) then
- queue_scroll = queue_scroll + 1
- drawMenu()
- drawFrontend()
- end
- elseif key == keys.a or key == keys.left then
- if menu_option > 1 then
- menu_option = menu_option - 1
- drawMenu()
- drawFrontend()
- end
- elseif key == keys.d or key == keys.right then
- if menu_option < 3 then
- menu_option = menu_option + 1
- drawMenu()
- drawFrontend()
- end
- elseif key == keys.enter then
- break
- end
- end
- end
- term.clear()
- if menu_option == 1 then
- displayAddSongArea()
- elseif menu_option == 2 then
- skipCurrentQueueItem()
- term.clear()
- displayQueueArea()
- elseif menu_option == 3 then
- shell.run("jukebox_frontend", JUKEBOX_ID, JUKEBOX_BACKEND_ID)
- end
- end
- local function gatherSongData()
- local song_list = fs.find("songs/*/*.json")
- for _, song_path in ipairs(song_list) do
- -- Decode data
- local song_file = fs.open(song_path, "r")
- local song_contents = song_file.readAll()
- song_file.close()
- local song_data = textutils.unserializeJSON(song_contents)
- local song_key = song_path
- if string.find(song_key, "songs/") ~= nil then
- song_key = string.sub(song_key, 7, #song_key - 5)
- end
- song_data["id"] = song_key
- -- Add to songs list
- songs_by_id[song_key] = song_data
- songs[#songs + 1] = song_data
- end
- end
- function main()
- rednet.send(
- JUKEBOX_BACKEND_ID,
- {
- action = "get_state"
- },
- protocol
- )
- while true do
- local id, message = rednet.receive(protocol)
- if message.type == "queue_update" then
- queue = message.queue
- current_song = message.current_song
- break
- end
- sleep(0.1)
- end
- gatherSongData()
- parallel.waitForAny(
- displayQueueArea,
- networkLoop
- )
- end
- main()
Advertisement
Add Comment
Please, Sign In to add comment