Advertisement
Guest User

Computercraft Streaming Music Program

a guest
Jul 25th, 2024
13,921
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.72 KB | None | 1 0
  1. local api_base_url = "https://ipod-2to6magyna-uc.a.run.app/"
  2.  
  3. local width, height = term.getSize()
  4.  
  5. local tab = 1
  6. local waiting_for_input = false
  7. local last_search = nil
  8. local last_search_url = nil
  9. local search_results = nil
  10. local search_error = false
  11. local in_fullscreen = 0
  12. local clicked_result = nil
  13.  
  14. local playing = false
  15. local queue = {}
  16. local now_playing = nil
  17. local looping = false
  18.  
  19. local playing_id = nil
  20. local last_download_url = nil
  21. local playing_status = 0
  22.  
  23. local player_handle = nil
  24. local start = nil
  25. local pcm = nil
  26. local size = nil
  27. local decoder = nil
  28. local needs_next_chunk = 0
  29. local buffer
  30.  
  31. local speakers = { peripheral.find("speaker") }
  32. if #speakers == 0 then
  33.     error("No speakers attached", 0)
  34. end
  35. local speaker = speakers[1]
  36.  
  37. os.startTimer(1)
  38.  
  39. local function redrawScreen()
  40.     if waiting_for_input == true then
  41.         return
  42.     end
  43.  
  44.     -- DRAWING
  45.     term.setBackgroundColor(colors.black)
  46.     term.clear()
  47.    
  48.     --tabs
  49.     term.setCursorPos(1,1)
  50.     term.setBackgroundColor(colors.gray)
  51.     term.clearLine()
  52.    
  53.     tabs = {" Now Playing ", " Search "}
  54.    
  55.     for i=1,2,1 do
  56.         if tab == i then
  57.             term.setTextColor(colors.black)
  58.             term.setBackgroundColor(colors.white)
  59.         else
  60.             term.setTextColor(colors.white)
  61.             term.setBackgroundColor(colors.gray)
  62.         end
  63.        
  64.         term.setCursorPos((math.floor((width/2)*(i-0.5)))-math.ceil(#tabs[i]/2)+1, 1)
  65.         term.write(tabs[i])
  66.     end
  67.  
  68.     --now playing tab
  69.     if tab == 1 then
  70.         if now_playing ~= nil then
  71.             term.setBackgroundColor(colors.black)
  72.             term.setTextColor(colors.white)
  73.             term.setCursorPos(2,3)
  74.             term.write(now_playing.name)
  75.             term.setTextColor(colors.lightGray)
  76.             term.setCursorPos(2,4)
  77.             term.write(now_playing.artist)
  78.         else
  79.             term.setBackgroundColor(colors.black)
  80.             term.setTextColor(colors.lightGray)
  81.             term.setCursorPos(2,3)
  82.             term.write("Not playing")
  83.         end
  84.  
  85.         term.setTextColor(colors.white)
  86.         term.setBackgroundColor(colors.gray)
  87.  
  88.         if playing then
  89.             term.setCursorPos(2, 6)
  90.             term.write(" Stop ")
  91.         else
  92.             if now_playing ~= nil or #queue > 0 then
  93.                 term.setTextColor(colors.white)
  94.                 term.setBackgroundColor(colors.gray)
  95.             else
  96.                 term.setTextColor(colors.lightGray)
  97.                 term.setBackgroundColor(colors.gray)
  98.             end
  99.             term.setCursorPos(2, 6)
  100.             term.write(" Play ")
  101.         end
  102.  
  103.         if now_playing ~= nil or #queue > 0 then
  104.             term.setTextColor(colors.white)
  105.             term.setBackgroundColor(colors.gray)
  106.         else
  107.             term.setTextColor(colors.lightGray)
  108.             term.setBackgroundColor(colors.gray)
  109.         end
  110.         term.setCursorPos(2 + 8, 6)
  111.         term.write(" Skip ")
  112.  
  113.         if looping then
  114.             term.setTextColor(colors.black)
  115.             term.setBackgroundColor(colors.white)
  116.         else
  117.             term.setTextColor(colors.white)
  118.             term.setBackgroundColor(colors.gray)
  119.         end
  120.         term.setCursorPos(2 + 8 + 8, 6)
  121.         term.write(" Loop ")
  122.  
  123.         --search results
  124.         if #queue > 0 then
  125.             term.setBackgroundColor(colors.black)
  126.             for i=1,#queue do
  127.                 term.setTextColor(colors.white)
  128.                 term.setCursorPos(2,8 + (i-1)*2)
  129.                 term.write(queue[i].name)
  130.                 term.setTextColor(colors.lightGray)
  131.                 term.setCursorPos(2,9 + (i-1)*2)
  132.                 term.write(queue[i].artist)
  133.             end
  134.         end
  135.     end
  136.    
  137.     --search tab
  138.     if tab == 2 then
  139.  
  140.         -- search bar
  141.         for a=3,5,1 do
  142.             term.setCursorPos(2,a)
  143.             term.setTextColor(colors.lightGray)
  144.             term.setBackgroundColor(colors.lightGray)
  145.             for i=1,width-2,1 do
  146.                 term.write(" ")
  147.             end
  148.         end
  149.         term.setCursorPos(3,4)
  150.         term.setTextColor(colors.black)
  151.         term.write(last_search or "Search...")
  152.  
  153.         --search results
  154.         if search_results ~= nil then
  155.             term.setBackgroundColor(colors.black)
  156.             for i=1,#search_results do
  157.                 term.setTextColor(colors.white)
  158.                 term.setCursorPos(2,7 + (i-1)*2)
  159.                 term.write(search_results[i].name)
  160.                 term.setTextColor(colors.lightGray)
  161.                 term.setCursorPos(2,8 + (i-1)*2)
  162.                 term.write(search_results[i].artist)
  163.             end
  164.         else
  165.             term.setCursorPos(2,7)
  166.             term.setBackgroundColor(colors.black)
  167.             if search_error == true then
  168.                 term.setTextColor(colors.red)
  169.                 term.write("Error")
  170.             else
  171.                 if last_search_url ~= nil then
  172.                     term.setTextColor(colors.white)
  173.                     term.write("Searching...")
  174.                 else
  175.  
  176.                 end
  177.             end
  178.         end
  179.  
  180.         --fullscreen song options
  181.         if in_fullscreen == 1 then
  182.             term.setBackgroundColor(colors.black)
  183.             term.clear()
  184.             term.setCursorPos(2,2)
  185.             term.setTextColor(colors.white)
  186.             term.write(search_results[clicked_result].name)
  187.             term.setCursorPos(2,3)
  188.             term.setTextColor(colors.lightGray)
  189.             term.write(search_results[clicked_result].artist)
  190.  
  191.             term.setBackgroundColor(colors.gray)
  192.             term.setTextColor(colors.white)
  193.  
  194.             term.setCursorPos(2,6)
  195.             term.clearLine()
  196.             term.write("Play now")
  197.  
  198.             term.setCursorPos(2,8)
  199.             term.clearLine()
  200.             term.write("Play next")
  201.  
  202.             term.setCursorPos(2,10)
  203.             term.clearLine()
  204.             term.write("Add to queue")
  205.  
  206.             term.setCursorPos(2,13)
  207.             term.clearLine()
  208.             term.write("Cancel")
  209.         end
  210.        
  211.     end
  212. end
  213.  
  214. local function searchInput()
  215.     while true do
  216.         if waiting_for_input == true then
  217.             for a=3,5,1 do
  218.                 term.setCursorPos(2,a)
  219.                 term.setTextColor(colors.white)
  220.                 term.setBackgroundColor(colors.white)
  221.                 for i=1,width-2,1 do
  222.                     term.write(" ")
  223.                 end
  224.             end
  225.             term.setCursorPos(3,4)
  226.             term.setTextColor(colors.black)
  227.             local input = read()
  228.             if string.len(input) > 0 then
  229.                 last_search = input
  230.                 last_search_url = api_base_url .. "?search=" .. textutils.urlEncode(input)
  231.                 http.request(last_search_url)
  232.                 search_results = nil
  233.                 search_error = false
  234.             else
  235.                 last_search = nil
  236.                 last_search_url = nil
  237.                 search_results = nil
  238.                 search_error = false
  239.             end
  240.        
  241.             waiting_for_input = false
  242.  
  243.             redrawScreen()
  244.         end
  245.  
  246.         sleep(0.1)
  247.     end
  248. end
  249.  
  250. local function mainLoop()
  251.     redrawScreen()
  252.  
  253.     while true do
  254.  
  255.         -- AUDIO
  256.         if playing and now_playing then
  257.             if playing_id ~= now_playing.id then
  258.                 playing_id = now_playing.id
  259.                 last_download_url = api_base_url .. "?id=" .. textutils.urlEncode(playing_id)
  260.                 playing_status = 0
  261.                 needs_next_chunk = 1
  262.  
  263.                 http.request({url = last_download_url, binary = true})
  264.  
  265.                 redrawScreen()
  266.             end
  267.             if playing_status == 1 and needs_next_chunk == 3 then
  268.                 needs_next_chunk = 1
  269.                 while not speaker.playAudio(buffer) do
  270.                     needs_next_chunk = 2
  271.                     break
  272.                 end
  273.             end
  274.             if playing_status == 1 and needs_next_chunk == 1 then
  275.  
  276.                 while true do
  277.                     local chunk = player_handle.read(size)
  278.                     if not chunk then
  279.                         if looping then
  280.                             playing_id = nil
  281.                         else
  282.                             if #queue > 0 then
  283.                                 now_playing = queue[1]
  284.                                 table.remove(queue, 1)
  285.                                 playing_id = nil
  286.                             else
  287.                                 now_playing = nil
  288.                                 playing = false
  289.                                 playing_id = nil
  290.                             end
  291.                         end
  292.  
  293.                         redrawScreen()
  294.  
  295.                         player_handle.close()
  296.                         needs_next_chunk = 0
  297.                         break
  298.                     else
  299.                         if start then
  300.                             chunk, start = start .. chunk, nil
  301.                             size = size + 4
  302.                         end
  303.                
  304.                         buffer = decoder(chunk)
  305.                         while not speaker.playAudio(buffer) do
  306.                             needs_next_chunk = 2
  307.                             break
  308.                         end
  309.                         if needs_next_chunk == 2 then
  310.                             break
  311.                         end
  312.                     end
  313.                 end
  314.  
  315.             end
  316.         end
  317.        
  318.         -- EVENTS
  319.         local event, param1, param2, param3 = os.pullEvent()   
  320.  
  321.         -- CLICK EVENTS
  322.         if event == "mouse_click" and waiting_for_input == false then
  323.  
  324.             local button = param1
  325.             local x = param2
  326.             local y = param3
  327.  
  328.             -- tabs
  329.             if button == 1 and in_fullscreen == 0 then
  330.                 if y == 1 then
  331.                     if x < width/2 then
  332.                         tab = 1
  333.                     else
  334.                         tab = 2
  335.                     end
  336.                 end
  337.             end
  338.  
  339.             --fullscreen windows
  340.             if in_fullscreen == 1 then
  341.                 term.setBackgroundColor(colors.white)
  342.                 term.setTextColor(colors.black)
  343.  
  344.                 if y == 6 then
  345.                     term.setCursorPos(2,6)
  346.                     term.clearLine()
  347.                     term.write("Play now")
  348.                     sleep(0.2)
  349.                     in_fullscreen = 0
  350.                     now_playing = search_results[clicked_result]
  351.                     playing = true
  352.                     playing_id = nil
  353.                 end
  354.  
  355.                 if y == 8 then
  356.                     term.setCursorPos(2,8)
  357.                     term.clearLine()
  358.                     term.write("Play next")
  359.                     sleep(0.2)
  360.                     in_fullscreen = 0
  361.                     table.insert(queue, 1, search_results[clicked_result])
  362.                 end
  363.  
  364.                 if y == 10 then
  365.                     term.setCursorPos(2,10)
  366.                     term.clearLine()
  367.                     term.write("Add to queue")
  368.                     sleep(0.2)
  369.                     in_fullscreen = 0
  370.                     table.insert(queue, search_results[clicked_result])
  371.                 end
  372.  
  373.                 if y == 13 then
  374.                     term.setCursorPos(2,13)
  375.                     term.clearLine()
  376.                     term.write("Cancel")
  377.                     sleep(0.2)
  378.                     in_fullscreen = 0
  379.                 end
  380.             else
  381.  
  382.                 -- now playing tab
  383.                 if tab == 1 and button == 1 then
  384.                     if y == 6 then
  385.                         if x >= 2 and x <= 2 + 6 then
  386.                             local animate = false
  387.                             local was_playing = playing
  388.                             if playing then
  389.                                 playing = false
  390.                                 animate = true
  391.                                 speaker.stop()
  392.                                 playing_id = nil
  393.                             else
  394.                                 if now_playing ~= nil then
  395.                                     playing_id = nil
  396.                                     playing = true
  397.                                     animate = true
  398.                                 else
  399.                                     if #queue > 0 then
  400.                                         now_playing = queue[1]
  401.                                         table.remove(queue, 1)
  402.                                         playing_id = nil
  403.                                         playing = true
  404.                                         animate = true
  405.                                     end
  406.                                 end
  407.                             end
  408.                             if animate == true then
  409.                                 term.setBackgroundColor(colors.white)
  410.                                 term.setTextColor(colors.black)
  411.                                 term.setCursorPos(2, 6)
  412.                                 if was_playing then
  413.                                     term.write(" Stop ")
  414.                                 else
  415.                                     term.write(" Play ")
  416.                                 end
  417.                                 sleep(0.2)
  418.                             end
  419.                         end
  420.                         if x >= 2 + 8 and x <= 2 + 8 + 6 then
  421.                             local animate = false
  422.                             if playing then
  423.                                 speaker.stop()
  424.                             end
  425.                             if now_playing ~= nil or #queue > 0 then
  426.                                 if #queue > 0 then
  427.                                     now_playing = queue[1]
  428.                                     table.remove(queue, 1)
  429.                                     playing_id = nil
  430.                                 else
  431.                                     now_playing = nil
  432.                                     playing = false
  433.                                     playing_id = nil
  434.                                 end
  435.                                 animate = true
  436.                             end
  437.                             if animate == true then
  438.                                 term.setBackgroundColor(colors.white)
  439.                                 term.setTextColor(colors.black)
  440.                                 term.setCursorPos(2 + 8, 6)
  441.                                 term.write(" Skip ")
  442.                                 sleep(0.2)
  443.                             end
  444.                         end
  445.                         if x >= 2 + 8 + 8 and x <= 2 + 8 + 8 + 6 then
  446.                             if looping then
  447.                                 looping = false
  448.                             else
  449.                                 looping = true
  450.                             end
  451.                         end
  452.                     end
  453.                 end
  454.  
  455.                 -- search tab clicks
  456.                 if tab == 2 and button == 1 then
  457.                     -- search box click
  458.                     if y >= 3 and y <= 5 and x >= 1 and x <= width-1 then
  459.                         waiting_for_input = true
  460.                     end
  461.  
  462.                     -- search result click
  463.                     if search_results then
  464.                         for i=1,#search_results do
  465.                             if y == 7 + (i-1)*2 or y == 8 + (i-1)*2 then
  466.                                 term.setBackgroundColor(colors.white)
  467.                                 term.setTextColor(colors.black)
  468.                                 term.setCursorPos(2,7 + (i-1)*2)
  469.                                 term.clearLine()
  470.                                 term.write(search_results[i].name)
  471.                                 term.setTextColor(colors.gray)
  472.                                 term.setCursorPos(2,8 + (i-1)*2)
  473.                                 term.clearLine()
  474.                                 term.write(search_results[i].artist)
  475.                                 sleep(0.2)
  476.                                 in_fullscreen = 1
  477.                                 clicked_result = i
  478.                             end
  479.                         end
  480.                     end
  481.                 end
  482.             end
  483.  
  484.             redrawScreen()
  485.  
  486.         end
  487.  
  488.         -- HTTP EVENTS
  489.         if event == "http_success" then
  490.             local url = param1
  491.             local handle = param2
  492.  
  493.             if url == last_search_url then
  494.                 search_results = textutils.unserialiseJSON(handle.readAll())
  495.                 redrawScreen()
  496.             end
  497.             if url == last_download_url then
  498.                 player_handle = handle
  499.                 start = handle.read(4)
  500.                 size = 16 * 1024 - 4
  501.                 if start == "RIFF" then
  502.                     error("WAV not supported!")
  503.                 end
  504.                 playing_status = 1
  505.                 decoder = require "cc.audio.dfpwm".make_decoder()
  506.             end
  507.         end
  508.  
  509.         if event == "http_failure" then
  510.             local url = param1
  511.  
  512.             if url == last_search_url then
  513.                 search_error = true
  514.                 redrawScreen()
  515.             end
  516.             if url == last_download_url then
  517.                 if #queue > 0 then
  518.                     now_playing = queue[1]
  519.                     table.remove(queue, 1)
  520.                     playing_id = nil
  521.                 else
  522.                     now_playing = nil
  523.                     playing = false
  524.                     playing_id = nil
  525.                 end
  526.                 redrawScreen()
  527.             end
  528.         end
  529.  
  530.         if event == "timer" then
  531.             os.startTimer(1)
  532.         end
  533.  
  534.         if event == "speaker_audio_empty" then
  535.             if needs_next_chunk == 2 then
  536.                 needs_next_chunk = 3
  537.             end
  538.         end
  539.  
  540.     end
  541.  
  542.     sleep(0.1)
  543. end
  544.  
  545. parallel.waitForAny(mainLoop, searchInput)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement