Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local api_base_url = "https://ipod-2to6magyna-uc.a.run.app/"
- local version = "2.1"
- local width, height = term.getSize()
- local tab = 1
- local waiting_for_input = false
- local last_search = nil
- local last_search_url = nil
- local search_results = nil
- local search_error = false
- local in_search_result = false
- local clicked_result = nil
- local playing = false
- local queue = {}
- local now_playing = nil
- local looping = 0
- local volume = 1.5
- local playing_id = nil
- local last_download_url = nil
- local playing_status = 0
- local is_loading = false
- local is_error = false;
- local player_handle = nil
- local start = nil
- local pcm = nil
- local size = nil
- local decoder = require "cc.audio.dfpwm".make_decoder()
- local needs_next_chunk = 0
- local buffer
- local speakers = { peripheral.find("speaker") }
- if #speakers == 0 then
- error("No speakers attached. You need to connect a speaker to this computer. If this is an Advanced Noisy Pocket Computer, then this is a bug, and you should try restarting your Minecraft game.", 0)
- end
- function redrawScreen()
- if waiting_for_input then
- return
- end
- term.setCursorBlink(false) -- Make sure cursor is off when redrawing
- -- Clear the screen
- term.setBackgroundColor(colors.black)
- term.clear()
- --Draw the three top tabs
- term.setCursorPos(1,1)
- term.setBackgroundColor(colors.gray)
- term.clearLine()
- tabs = {" Now Playing ", " Search "}
- for i=1,#tabs,1 do
- if tab == i then
- term.setTextColor(colors.black)
- term.setBackgroundColor(colors.white)
- else
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.gray)
- end
- term.setCursorPos((math.floor((width/#tabs)*(i-0.5)))-math.ceil(#tabs[i]/2)+1, 1)
- term.write(tabs[i])
- end
- if tab == 1 then
- drawNowPlaying()
- elseif tab == 2 then
- drawSearch()
- end
- end
- function drawNowPlaying()
- if now_playing ~= nil then
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.setCursorPos(2,3)
- term.write(now_playing.name)
- term.setTextColor(colors.lightGray)
- term.setCursorPos(2,4)
- term.write(now_playing.artist)
- else
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.lightGray)
- term.setCursorPos(2,3)
- term.write("Not playing")
- end
- if is_loading == true then
- term.setTextColor(colors.gray)
- term.setBackgroundColor(colors.black)
- term.setCursorPos(2,5)
- term.write("Loading...")
- elseif is_error == true then
- term.setTextColor(colors.red)
- term.setBackgroundColor(colors.black)
- term.setCursorPos(2,5)
- term.write("Network error")
- end
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.gray)
- if playing then
- term.setCursorPos(2, 6)
- term.write(" Stop ")
- else
- if now_playing ~= nil or #queue > 0 then
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.gray)
- else
- term.setTextColor(colors.lightGray)
- term.setBackgroundColor(colors.gray)
- end
- term.setCursorPos(2, 6)
- term.write(" Play ")
- end
- if now_playing ~= nil or #queue > 0 then
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.gray)
- else
- term.setTextColor(colors.lightGray)
- term.setBackgroundColor(colors.gray)
- end
- term.setCursorPos(2 + 7, 6)
- term.write(" Skip ")
- if looping ~= 0 then
- term.setTextColor(colors.black)
- term.setBackgroundColor(colors.white)
- else
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.gray)
- end
- term.setCursorPos(2 + 7 + 7, 6)
- if looping == 0 then
- term.write(" Loop Off ")
- elseif looping == 1 then
- term.write(" Loop Queue ")
- else
- term.write(" Loop Song ")
- end
- term.setCursorPos(2,8)
- paintutils.drawBox(2,8,25,8,colors.gray)
- local width = math.floor(24 * (volume / 3) + 0.5)-1
- if not (width == -1) then
- paintutils.drawBox(2,8,2+width,8,colors.white)
- end
- if volume < 0.6 then
- term.setCursorPos(2+width+2,8)
- term.setBackgroundColor(colors.gray)
- term.setTextColor(colors.white)
- else
- term.setCursorPos(2+width-3-(volume == 3 and 1 or 0),8)
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- end
- term.write(math.floor(100 * (volume / 3) + 0.5) .. "%")
- if #queue > 0 then
- term.setBackgroundColor(colors.black)
- for i=1,#queue do
- term.setTextColor(colors.white)
- term.setCursorPos(2,10 + (i-1)*2)
- term.write(queue[i].name)
- term.setTextColor(colors.lightGray)
- term.setCursorPos(2,11 + (i-1)*2)
- term.write(queue[i].artist)
- end
- end
- end
- function drawSearch()
- -- Search bar
- paintutils.drawFilledBox(2,3,width-1,5,colors.lightGray)
- term.setBackgroundColor(colors.lightGray)
- term.setCursorPos(3,4)
- term.setTextColor(colors.black)
- term.write(last_search or "Search...")
- --Search results
- if search_results ~= nil then
- term.setBackgroundColor(colors.black)
- for i=1,#search_results do
- term.setTextColor(colors.white)
- term.setCursorPos(2,7 + (i-1)*2)
- term.write(search_results[i].name)
- term.setTextColor(colors.lightGray)
- term.setCursorPos(2,8 + (i-1)*2)
- term.write(search_results[i].artist)
- end
- else
- term.setCursorPos(2,7)
- term.setBackgroundColor(colors.black)
- if search_error == true then
- term.setTextColor(colors.red)
- term.write("Network error")
- elseif last_search_url ~= nil then
- term.setTextColor(colors.lightGray)
- term.write("Searching...")
- else
- term.setCursorPos(1,7)
- term.setTextColor(colors.lightGray)
- print("Tip: You can paste YouTube video or playlist links.")
- end
- end
- --fullscreen song options
- if in_search_result == true then
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(2,2)
- term.setTextColor(colors.white)
- term.write(search_results[clicked_result].name)
- term.setCursorPos(2,3)
- term.setTextColor(colors.lightGray)
- term.write(search_results[clicked_result].artist)
- term.setBackgroundColor(colors.gray)
- term.setTextColor(colors.white)
- term.setCursorPos(2,6)
- term.clearLine()
- term.write("Play now")
- term.setCursorPos(2,8)
- term.clearLine()
- term.write("Play next")
- term.setCursorPos(2,10)
- term.clearLine()
- term.write("Add to queue")
- term.setCursorPos(2,13)
- term.clearLine()
- term.write("Cancel")
- end
- end
- function uiLoop()
- redrawScreen()
- while true do
- if waiting_for_input then
- parallel.waitForAny(
- function()
- term.setCursorPos(3,4)
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- local input = read()
- if string.len(input) > 0 then
- last_search = input
- last_search_url = api_base_url .. "?v=" .. version .. "&search=" .. textutils.urlEncode(input)
- http.request(last_search_url)
- search_results = nil
- search_error = false
- else
- last_search = nil
- last_search_url = nil
- search_results = nil
- search_error = false
- end
- waiting_for_input = false
- os.queueEvent("redraw_screen")
- end,
- function()
- while waiting_for_input do
- local event, button, x, y = os.pullEvent("mouse_click")
- if y < 3 or y > 5 or x < 2 or x > width-1 then
- waiting_for_input = false
- os.queueEvent("redraw_screen")
- break
- end
- end
- end
- )
- else
- parallel.waitForAny(
- function()
- local event, button, x, y = os.pullEvent("mouse_click")
- if button == 1 then
- -- Tabs
- if in_search_result == false then
- if y == 1 then
- if x < width/2 then
- tab = 1
- else
- tab = 2
- end
- redrawScreen()
- end
- end
- if tab == 2 and in_search_result == false then
- -- Search box click
- if y >= 3 and y <= 5 and x >= 1 and x <= width-1 then
- paintutils.drawFilledBox(2,3,width-1,5,colors.white)
- term.setBackgroundColor(colors.white)
- waiting_for_input = true
- end
- -- Search result click
- if search_results then
- for i=1,#search_results do
- if y == 7 + (i-1)*2 or y == 8 + (i-1)*2 then
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- term.setCursorPos(2,7 + (i-1)*2)
- term.clearLine()
- term.write(search_results[i].name)
- term.setTextColor(colors.gray)
- term.setCursorPos(2,8 + (i-1)*2)
- term.clearLine()
- term.write(search_results[i].artist)
- sleep(0.2)
- in_search_result = true
- clicked_result = i
- redrawScreen()
- end
- end
- end
- elseif tab == 2 and in_search_result == true then
- -- Search result menu clicks
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- if y == 6 then
- term.setCursorPos(2,6)
- term.clearLine()
- term.write("Play now")
- sleep(0.2)
- in_search_result = false
- for _, speaker in ipairs(speakers) do
- speaker.stop()
- os.queueEvent("playback_stopped")
- end
- playing = true
- is_error = false
- playing_id = nil
- if search_results[clicked_result].type == "playlist" then
- now_playing = search_results[clicked_result].playlist_items[1]
- queue = {}
- if #search_results[clicked_result].playlist_items > 1 then
- for i=2, #search_results[clicked_result].playlist_items do
- table.insert(queue, search_results[clicked_result].playlist_items[i])
- end
- end
- else
- now_playing = search_results[clicked_result]
- end
- os.queueEvent("audio_update")
- end
- if y == 8 then
- term.setCursorPos(2,8)
- term.clearLine()
- term.write("Play next")
- sleep(0.2)
- in_search_result = false
- if search_results[clicked_result].type == "playlist" then
- for i = #search_results[clicked_result].playlist_items, 1, -1 do
- table.insert(queue, 1, search_results[clicked_result].playlist_items[i])
- end
- else
- table.insert(queue, 1, search_results[clicked_result])
- end
- os.queueEvent("audio_update")
- end
- if y == 10 then
- term.setCursorPos(2,10)
- term.clearLine()
- term.write("Add to queue")
- sleep(0.2)
- in_search_result = false
- if search_results[clicked_result].type == "playlist" then
- for i = 1, #search_results[clicked_result].playlist_items do
- table.insert(queue, search_results[clicked_result].playlist_items[i])
- end
- else
- table.insert(queue, search_results[clicked_result])
- end
- os.queueEvent("audio_update")
- end
- if y == 13 then
- term.setCursorPos(2,13)
- term.clearLine()
- term.write("Cancel")
- sleep(0.2)
- in_search_result = false
- end
- redrawScreen()
- elseif tab == 1 and in_search_result == false then
- -- Now playing tab clicks
- if y == 6 then
- -- Play/stop button
- if x >= 2 and x < 2 + 6 then
- if playing or now_playing ~= nil or #queue > 0 then
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- term.setCursorPos(2, 6)
- if playing then
- term.write(" Stop ")
- else
- term.write(" Play ")
- end
- sleep(0.2)
- end
- if playing then
- playing = false
- for _, speaker in ipairs(speakers) do
- speaker.stop()
- os.queueEvent("playback_stopped")
- end
- playing_id = nil
- is_loading = false
- is_error = false
- os.queueEvent("audio_update")
- elseif now_playing ~= nil then
- playing_id = nil
- playing = true
- is_error = false
- os.queueEvent("audio_update")
- elseif #queue > 0 then
- now_playing = queue[1]
- table.remove(queue, 1)
- playing_id = nil
- playing = true
- is_error = false
- os.queueEvent("audio_update")
- end
- end
- -- Skip button
- if x >= 2 + 7 and x < 2 + 7 + 6 then
- if now_playing ~= nil or #queue > 0 then
- term.setBackgroundColor(colors.white)
- term.setTextColor(colors.black)
- term.setCursorPos(2 + 7, 6)
- term.write(" Skip ")
- sleep(0.2)
- is_error = false
- if playing then
- for _, speaker in ipairs(speakers) do
- speaker.stop()
- os.queueEvent("playback_stopped")
- end
- end
- if #queue > 0 then
- if looping == 1 then
- table.insert(queue, now_playing)
- end
- now_playing = queue[1]
- table.remove(queue, 1)
- playing_id = nil
- else
- now_playing = nil
- playing = false
- is_loading = false
- is_error = false
- playing_id = nil
- end
- os.queueEvent("audio_update")
- end
- end
- -- Loop button
- if x >= 2 + 7 + 7 and x < 2 + 7 + 7 + 12 then
- if looping == 0 then
- looping = 1
- elseif looping == 1 then
- looping = 2
- else
- looping = 0
- end
- end
- end
- if y == 8 then
- -- Volume slider
- if x >= 1 and x < 2 + 24 then
- volume = (x - 1) / 24 * 3
- -- for _, speaker in ipairs(speakers) do
- -- speaker.stop()
- -- os.queueEvent("playback_stopped")
- -- end
- -- playing_id = nil
- -- os.queueEvent("audio_update")
- end
- end
- redrawScreen()
- end
- end
- end,
- function()
- local event, button, x, y = os.pullEvent("mouse_drag")
- if button == 1 then
- if tab == 1 and in_search_result == false then
- if y >= 7 and y <= 9 then
- -- Volume slider
- if x >= 1 and x < 2 + 24 then
- volume = (x - 1) / 24 * 3
- -- for _, speaker in ipairs(speakers) do
- -- speaker.stop()
- -- os.queueEvent("playback_stopped")
- -- end
- -- playing_id = nil
- -- os.queueEvent("audio_update")
- end
- end
- redrawScreen()
- end
- end
- end,
- function()
- local event = os.pullEvent("redraw_screen")
- redrawScreen()
- end
- )
- end
- end
- end
- function audioLoop()
- while true do
- -- AUDIO
- if playing and now_playing then
- local thisnowplayingid = now_playing.id
- if playing_id ~= thisnowplayingid then
- playing_id = thisnowplayingid
- last_download_url = api_base_url .. "?v=" .. version .. "&id=" .. textutils.urlEncode(playing_id)
- playing_status = 0
- needs_next_chunk = 1
- http.request({url = last_download_url, binary = true})
- is_loading = true
- os.queueEvent("redraw_screen")
- os.queueEvent("audio_update")
- elseif playing_status == 1 and needs_next_chunk == 1 then
- while true do
- local chunk = player_handle.read(size)
- if not chunk then
- if looping == 2 or (looping == 1 and #queue == 0) then
- playing_id = nil
- elseif looping == 1 and #queue > 0 then
- table.insert(queue, now_playing)
- now_playing = queue[1]
- table.remove(queue, 1)
- playing_id = nil
- else
- if #queue > 0 then
- now_playing = queue[1]
- table.remove(queue, 1)
- playing_id = nil
- else
- now_playing = nil
- playing = false
- playing_id = nil
- is_loading = false
- is_error = false
- end
- end
- os.queueEvent("redraw_screen")
- player_handle.close()
- needs_next_chunk = 0
- break
- else
- if start then
- chunk, start = start .. chunk, nil
- size = size + 4
- end
- buffer = decoder(chunk)
- local fn = {}
- for i, speaker in ipairs(speakers) do
- fn[i] = function()
- local name = peripheral.getName(speaker)
- if #speakers > 1 then
- if speaker.playAudio(buffer, volume) then
- parallel.waitForAny(
- function()
- repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
- end,
- function()
- local event = os.pullEvent("playback_stopped")
- return
- end
- )
- if not playing or playing_id ~= thisnowplayingid then
- return
- end
- end
- else
- while not speaker.playAudio(buffer, volume) do
- parallel.waitForAny(
- function()
- repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
- end,
- function()
- local event = os.pullEvent("playback_stopped")
- return
- end
- )
- if not playing or playing_id ~= thisnowplayingid then
- return
- end
- end
- end
- if not playing or playing_id ~= thisnowplayingid then
- return
- end
- end
- end
- local ok, err = pcall(parallel.waitForAll, table.unpack(fn))
- if not ok then
- needs_next_chunk = 2
- is_error = true
- break
- end
- -- If we're not playing anymore, exit the chunk processing loop
- if not playing or playing_id ~= thisnowplayingid then
- break
- end
- end
- end
- os.queueEvent("audio_update")
- end
- end
- os.pullEvent("audio_update")
- end
- end
- function httpLoop()
- while true do
- parallel.waitForAny(
- function()
- local event, url, handle = os.pullEvent("http_success")
- if url == last_search_url then
- search_results = textutils.unserialiseJSON(handle.readAll())
- os.queueEvent("redraw_screen")
- end
- if url == last_download_url then
- is_loading = false
- player_handle = handle
- start = handle.read(4)
- size = 16 * 1024 - 4
- playing_status = 1
- os.queueEvent("redraw_screen")
- os.queueEvent("audio_update")
- end
- end,
- function()
- local event, url = os.pullEvent("http_failure")
- if url == last_search_url then
- search_error = true
- os.queueEvent("redraw_screen")
- end
- if url == last_download_url then
- is_loading = false
- is_error = true
- playing = false
- playing_id = nil
- os.queueEvent("redraw_screen")
- os.queueEvent("audio_update")
- end
- end
- )
- end
- end
- parallel.waitForAny(uiLoop, audioLoop, httpLoop)
Add Comment
Please, Sign In to add comment