Advertisement
HydrantHunter

ccTuner

Nov 11th, 2015
867
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.36 KB | None | 0 0
  1. --[[    ccTuner    ]]--
  2. --[[  for  OpenFM  ]]--
  3. --[[      by       ]]--
  4. --[[ HydrantHunter ]]--
  5. --[[   aka  Dog    ]]--
  6. --[[   Pastebin:   ]]--
  7. --[[   hKuKNEcM    ]]--
  8. local ccTunerVer = "1.0.04"
  9. --[[
  10. fm.setScreenColor(0xFF0000) --Sets the screen color to red
  11. fm.getScreenColor()
  12. ]]--
  13. local termX, termY = term.getSize()
  14. local menu, mute = false, false
  15. local currentStation, nowPlaying, radioVolume = 0, 0, 0
  16. local pageNum, numPages, numPerPage = 1, 1, 36
  17. local screen, stationList = "tuner", "/data/FMstations"
  18. local fm
  19. local sources = {
  20.   ["Radionomy"] = "http://listen.radionomy.com/",
  21.   ["Other    "] = "",
  22. }
  23. local radioStations = {
  24.   { name = "Deep House", site = "Radionomy", channel = "DeepHouse" };
  25.   { name = "Urban Hotspot", site = "Radionomy", channel = "AllUrbanHotSpot" };
  26.   { name = "Flavor Remix", site = "Radionomy", channel = "McDonald-sFlavorBattleRadio" };
  27.   { name = "One Hip Hop", site = "Radionomy", channel = "One-love-Hip-Hop-Radio" };
  28.   { name = "Boss Boss", site = "Radionomy", channel = "BossBossRadio" };
  29.   { name = "Classic Rock", site = "Radionomy", channel = "-1ClassicRock" };
  30.   { name = "Underground", site = "Radionomy", channel = "3WKCOMClassicUndergroundradio" };
  31.   { name = "Smooth Jazz", site = "Radionomy", channel = "all-smooth-jazz" };
  32.   { name = "Smooth Jazz 2", site = "Other    ", channel = "http://173.244.199.249:80" };
  33. }
  34.  
  35. local function saveData()
  36.   if not fs.exists("/data") then fs.makeDir("/data") end
  37.   local stationData = fs.open(stationList, "w")
  38.   stationData.write(textutils.serialize(radioStations))
  39.   stationData.close()
  40. end
  41.  
  42. local function clearLowerScreen(bgColor)
  43.   paintutils.drawFilledBox(1, 4, termX, termY, bgColor or colors.black)
  44. end
  45.  
  46. local function drawRadioVolume()
  47.   term.setBackgroundColor(colors.blue)
  48.   term.setTextColor(mute and colors.lightGray or colors.white)
  49.   term.setCursorPos(6, 2)
  50.   term.write("0" .. tostring(radioVolume))
  51. end
  52.  
  53. local function drawHeader()
  54.   paintutils.drawBox(1, 1, 3, 3, colors.white)       --# STOP button body
  55.   paintutils.drawFilledBox(4, 1, 48, 3, colors.blue) --# Header body
  56.   paintutils.drawBox(49, 1, termX, 3, colors.red)    --# Close button body
  57.   term.setTextColor(colors.white)
  58.   term.setCursorPos(2, 2)
  59.   term.write(" ")                          --# STOP button center
  60.   term.setCursorPos(termX - 1, 2)
  61.   term.write("X")                          --# Close button 'X'
  62.   term.setBackgroundColor(colors.white)
  63.   term.setTextColor(colors.black)
  64.   term.setCursorPos(5, 1)
  65.   term.write(" /\\ ")                      --# VOL UP
  66.   term.setCursorPos(5, 3)
  67.   term.write(" \\/ ")                      --# VOL DN
  68.   drawRadioVolume()                        --# volume level
  69.   term.setTextColor(colors.lightBlue)
  70.   term.setCursorPos(23, 2)
  71.   term.write("ccTuner")                    --# title
  72. end
  73.  
  74. local function drawSourceMenu()
  75.   term.setBackgroundColor(colors.gray)
  76.   term.setTextColor(colors.white)
  77.   local y = 7
  78.   for source in pairs(sources) do
  79.     y = y + 1
  80.     term.setCursorPos(8, y)
  81.     term.write(" " .. source .. " ")
  82.   end
  83. end
  84.  
  85. local function drawRadioStationInfo()
  86.   clearLowerScreen()
  87.   term.setTextColor(colors.white)
  88.   term.setCursorPos(2, 5)
  89.   term.write("Name: ")
  90.   term.setTextColor(colors.lightGray)
  91.   term.write(radioStations[currentStation].name)               --# Name
  92.   term.setTextColor(colors.white)
  93.   term.setCursorPos(2, 7)
  94.   term.write("Site: ")
  95.   term.setBackgroundColor(colors.lightGray)
  96.   term.setTextColor(colors.black)
  97.   term.write(" " .. radioStations[currentStation].site .. " ") --# Site / Source
  98.   term.setBackgroundColor(colors.gray)
  99.   term.setTextColor(colors.white)
  100.   term.write("v")
  101.   term.setBackgroundColor(colors.black)
  102.   term.setCursorPos(2, 9)
  103.   term.write("Channel: ")
  104.   term.setTextColor(colors.lightGray)
  105.   term.write(radioStations[currentStation].channel)            --# Channel
  106.   term.setTextColor(colors.white)
  107.   term.setCursorPos(2, 11)
  108.   term.write("Station #: ")
  109.   term.setTextColor(colors.lightGray)
  110.   term.write(tostring(currentStation))                         --# Number in list
  111.   term.setCursorPos(2, 13)
  112.   if nowPlaying == currentStation then
  113.     term.setTextColor(colors.green)
  114.     term.write("This station is now playing")
  115.   else
  116.     term.setTextColor(colors.white)
  117.     term.setBackgroundColor(colors.green)
  118.     term.write(" PLAY ")
  119.   end
  120. end
  121.  
  122. local function drawTunerScreen()
  123.   clearLowerScreen()
  124.   local magicNumber = ((pageNum - 1) * numPerPage) + 1
  125.   local xPos, yPos = 2, 5
  126.   for i = magicNumber, math.min(pageNum * numPerPage, #radioStations) do --# start station entries loop
  127.     term.setCursorPos(xPos, yPos)
  128.     term.setTextColor(colors.white)
  129.     term.setBackgroundColor(i == nowPlaying and colors.green or colors.black)
  130.     term.write(radioStations[i].name:sub(1, 15))    --# write the entry to screen
  131.     if i >= #radioStations then break end           --# break the loop if at the end of the list
  132.     yPos = yPos + 1
  133.     if yPos >= 17 then xPos = xPos + 17 yPos = 5 end
  134.   end
  135.   if numPages > 1 then                              --# show page navigation controls if more than one page
  136.     term.setCursorPos(16, termY - 1)
  137.     term.setBackgroundColor(colors.black)
  138.     term.setTextColor(colors.lightGray)
  139.     term.write("<< <            > >>")              --# page navigation controls
  140.     local pages = tostring(pageNum) .. " of " .. tostring(numPages)
  141.     term.setCursorPos(math.ceil(termX / 2) - math.floor(#pages / 2), termY - 1)
  142.     term.write(pages)                               --# page number
  143.   end
  144.   term.setCursorPos(1, termY)
  145.   term.setBackgroundColor(colors.green)
  146.   term.setTextColor(colors.white)
  147.   term.write("                  Add new station                  ")
  148. end
  149.  
  150. local function drawHelpScreen()
  151.   clearLowerScreen(colors.white)
  152.   term.setTextColor(colors.gray)
  153.   term.setCursorPos(17, 5)
  154.   term.write("an entry to play")
  155.   term.setCursorPos(17, 7)
  156.   term.write("an entry to view/edit")
  157.   term.setCursorPos(17, 9)
  158.   term.write("an entry to delete")
  159.   term.setCursorPos(17, 12)
  160.   term.write("For Radionomy sources, the channel")
  161.   term.setCursorPos(17, 13)
  162.   term.write("is the last part of the listen URL")
  163.   term.setCursorPos(17, 15)
  164.   term.write("For Other sources, the channel")
  165.   term.setCursorPos(17, 16)
  166.   term.write("is the entire stream URL")
  167.   paintutils.drawFilledBox(1, 4, 15, termY, colors.lightGray)
  168.   term.setTextColor(colors.black)
  169.   term.setCursorPos(2, 5)
  170.   term.write("Left Click")
  171.   term.setCursorPos(2, 7)
  172.   term.write("Right Click")
  173.   term.setCursorPos(2, 9)
  174.   term.write("Middle Click")
  175.   term.setCursorPos(2, 12)
  176.   term.write("Sources")
  177.   term.setBackgroundColor(colors.gray)
  178.   term.setTextColor(colors.lightGray)
  179.   term.setCursorPos(1, termY)
  180.   term.write("                ccTuner ver. " .. ccTunerVer .. "                ")
  181. end
  182.  
  183. local function highlightButton(x, y, word)
  184.   term.setCursorPos(x, y)
  185.   term.setBackgroundColor(colors.orange)
  186.   term.setTextColor(colors.white)
  187.   term.write(word)
  188. end
  189.  
  190. local function userInputPreview(x, y, word)
  191.   term.setCursorPos(x, y)
  192.   term.setBackgroundColor(colors.black)
  193.   term.setTextColor(colors.gray)
  194.   term.write(word)
  195.   term.setTextColor(colors.white)
  196.   term.setCursorPos(x, y)
  197. end
  198.  
  199. local function userInput(x, y, word)
  200.   userInputPreview(x, y, word)
  201.   local newWord = read()
  202.   return newWord ~= "" and newWord or word
  203. end
  204.  
  205. local function queueMusic()
  206.   pcall(fm.stop)
  207.   pcall(fm.setURL, sources[radioStations[nowPlaying].site] .. radioStations[nowPlaying].channel)
  208.   pcall(fm.start)
  209.   pcall(fm.setScreenText, radioStations[nowPlaying].name) --# Text will scroll if larger than the display.
  210. end
  211.  
  212. local function userInput()
  213.   local event, data, mX, mY, xPos, yPos, magicNumber, tmpName, tmpSite, tmpChannel, newNum
  214.   while true do
  215.     event, data, mX, mY = os.pullEvent()
  216.     if event == "mouse_click" then
  217.       if mY < 4 and data == 1 then
  218.         if mX < 4 then                      --# STOP
  219.           pcall(fm.stop)
  220.           pcall(fm.setScreenText, "OpenFM") --# Text will scroll if larger than the display.
  221.           nowPlaying = 0
  222.           if screen == "tuner" then
  223.             drawTunerScreen()
  224.           elseif screen == "info" then
  225.             drawRadioStationInfo()
  226.           end
  227.         elseif mX > 4 and mX < 9 then
  228.           if mY == 1 then                   --# Volume UP
  229.             radioVolume = math.min(radioVolume + 1, 9)
  230.             if not mute then pcall(fm.volUp) end
  231.           elseif mY == 2 then               --# Mute / Unmute
  232.             mute = not mute
  233.             for i = 1, radioVolume do
  234.               pcall(mute and fm.volDown or fm.volUp)
  235.             end
  236.           elseif mY == 3 then               --# Volume DOWN
  237.             radioVolume = math.max(radioVolume - 1, 0)
  238.             if not mute then pcall(fm.volDown) end
  239.           end
  240.           drawRadioVolume()
  241.         elseif mX > termX - 3 then
  242.           if screen == "tuner" then         --# exit program
  243.             term.setBackgroundColor(colors.black)
  244.             term.setTextColor(colors.white)
  245.             term.clear()
  246.             term.setCursorPos(1, 1)
  247.             return
  248.           else                              --# return to tuner screen
  249.             screen = "tuner"
  250.             currentStation = 0
  251.             drawTunerScreen()
  252.           end
  253.         end
  254.       end
  255.       if screen == "tuner" then
  256.         if mY == termY and data == 1 then
  257.           radioStations[#radioStations + 1] = { name = "Deep House", site = "Radionomy", channel = "DeepHouse" }
  258.           saveData()
  259.           numPages = math.max(1, math.ceil(#radioStations / numPerPage))         --# paginate radio stations
  260.           currentStation = #radioStations
  261.           screen = "info"
  262.           drawRadioStationInfo()
  263.         elseif mY == termY - 1 and ((mX > 15 and mX < 20) or (mX > 31 and mX < 36)) and numPages > 1 and data == 1 then --# page navigation
  264.           if (mX > 15 and mX < 18) or (mX > 33 and mX < 36) then --# Home / End
  265.             pageNum = (mX > 15 and mX < 18) and 1 or numPages
  266.           elseif mX == 19 or mX == 32 then --# Page - / +
  267.             pageNum = mX == 19 and math.max(1, pageNum - 1) or math.min(pageNum + 1, numPages)
  268.           end
  269.           drawTunerScreen()
  270.         else
  271.           magicNumber = ((pageNum - 1) * numPerPage) + 1
  272.           xPos, yPos = 2, 5
  273.           for i = magicNumber, math.min(pageNum * numPerPage, #radioStations) do --# start click detection loop
  274.             if mX >= xPos and mX < xPos + #radioStations[i].name and mY == yPos then
  275.               if data == 1 and nowPlaying ~= i then                              --# Button 1 / play
  276.                 nowPlaying = 0
  277.                 drawTunerScreen()
  278.                 nowPlaying = i
  279.                 highlightButton(xPos, yPos, radioStations[i].name)
  280.                 queueMusic()
  281.                 drawTunerScreen()
  282.               elseif data == 2 then                                              --# Button 2 / edit
  283.                 screen = "info"
  284.                 currentStation = i
  285.                 drawRadioStationInfo()
  286.               elseif data == 3 and #radioStations > 1 then                       --# Button 3 / delete
  287.                 table.remove(radioStations, i)
  288.                 saveData()
  289.                 numPages = math.max(1, math.ceil(#radioStations / numPerPage)) --# paginate radio stations
  290.                 pageNum = math.min(pageNum, numPages)                          --# ensure pageNum is valid
  291.                 if nowPlaying == i then nowPlaying = 0 end
  292.                 if nowPlaying > i then nowPlaying = nowPlaying - 1 end
  293.                 drawTunerScreen()
  294.               end
  295.               break
  296.             end
  297.             yPos = yPos + 1
  298.             if yPos >= 17 then xPos = xPos + 17 yPos = 5 end
  299.           end
  300.         end
  301.       elseif screen == "info" and data == 1 and not menu then
  302.         if mY == 5 and mX > 7 and mX < 8 + #radioStations[currentStation].name then --# name
  303.           tmpName = userInput(8, 5, radioStations[currentStation].name)
  304.           if tmpName ~= radioStations[currentStation].name then
  305.             radioStations[currentStation].name = tmpName
  306.             saveData()
  307.           end
  308.           drawRadioStationInfo()
  309.         elseif mY == 7 and mX > 7 and mX < 11 + #radioStations[currentStation].site then --# site menu
  310.           menu = true
  311.           drawSourceMenu()
  312.         elseif mY == 9 and mX > 10 and mX < 11 + #radioStations[currentStation].channel then --# channel
  313.           tmpChannel = userInput(11, 9, radioStations[currentStation].channel)
  314.           if tmpChannel ~= radioStations[currentStation].channel then
  315.             radioStations[currentStation].channel = tmpChannel
  316.             if nowPlaying == currentStation then nowPlaying = 0 end
  317.             saveData()
  318.           end
  319.           drawRadioStationInfo()
  320.         elseif mY == 11 and mX > 12 and mX < 13 + #tostring(currentStation) then    --# number in list
  321.           newNum = tonumber(userInput(13, 11, tostring(currentStation)))
  322.           if newNum then newNum = math.floor(newNum) end
  323.           if newNum and newNum > 0 and newNum <= #radioStations and newNum ~= currentStation then
  324.             tmpName = radioStations[currentStation].name
  325.             tmpSite = radioStations[currentStation].site
  326.             tmpChannel = radioStations[currentStation].channel
  327.             table.remove(radioStations, currentStation)
  328.             table.insert(radioStations, newNum, { name = tmpName, site = tmpSite, channel = tmpChannel })
  329.             if nowPlaying == currentStation then
  330.               nowPlaying = newNum
  331.             elseif newNum <= nowPlaying and currentStation > nowPlaying then
  332.               nowPlaying = nowPlaying + 1
  333.             elseif newNum >= nowPlaying and currentStation < nowPlaying then
  334.               nowPlaying = nowPlaying - 1
  335.             end
  336.             currentStation = newNum
  337.             saveData()
  338.           end
  339.           drawRadioStationInfo()
  340.         elseif mY == 13 and mX > 1 and mX < 7 and currentStation ~= nowPlaying then --# play
  341.           nowPlaying = currentStation
  342.           highlightButton(2, 13, "Tuning")
  343.           queueMusic()
  344.           drawRadioStationInfo()
  345.         end
  346.       elseif screen == "info" and data == 1 and menu then                           --# Source selection menu
  347.         if mX > 7 and mX < 20 and mY > 7 and mY < 10 then
  348.           if mY == 8 and radioStations[currentStation].site ~= "Other    " then     --# Select 'Other'
  349.             radioStations[currentStation].site = "Other    "
  350.             if nowPlaying == currentStation then nowPlaying = 0 end
  351.             saveData()
  352.           elseif mY == 9 and radioStations[currentStation].site ~= "Radionomy" then --# Select 'Radionomy'
  353.             radioStations[currentStation].site = "Radionomy"
  354.             if nowPlaying == currentStation then nowPlaying = 0 end
  355.             saveData()
  356.           end
  357.         end
  358.         menu = false
  359.         drawRadioStationInfo()
  360.       end
  361.     elseif event == "mouse_scroll" then
  362.       if screen == "tuner" then
  363.         pageNum = data == 1 and math.min(pageNum + 1, numPages) or math.max(pageNum - 1, 1)
  364.         drawTunerScreen()
  365.       elseif screen == "info" and not menu then
  366.         currentStation = data == 1 and math.min(currentStation + 1, #radioStations) or math.max(currentStation - 1, 1)
  367.         drawRadioStationInfo()
  368.       end
  369.     elseif event == "key" then
  370.       if data == keys.f1 then --# F1
  371.         if screen == "help" or screen == "tuner" then
  372.           screen = screen == "help" and "tuner" or "help"
  373.           if screen == "help" then drawHelpScreen() else drawTunerScreen() end
  374.         end
  375.       elseif data == keys.pageDown or data == keys.pageUp then --# PageDN / PageUP
  376.         if screen == "tuner" then
  377.           pageNum = data == keys.pageDown and math.max(pageNum - 1, 1) or math.min(pageNum + 1, numPages)
  378.           drawTunerScreen()
  379.         elseif screen == "info" and not menu then
  380.           currentStation = data == keys.pageDown and math.max(currentStation - 1, 1) or math.min(currentStation + 1, #radioStations)
  381.           drawRadioStationInfo()
  382.         end
  383.       elseif data == keys.home or data == keys["end"] then --# Home / End
  384.         if screen == "tuner" then
  385.           pageNum = data == keys.home and 1 or numPages
  386.           drawTunerScreen()
  387.         elseif screen == "info" and not menu then
  388.           currentStation = data == keys.home and 1 or #radioStations
  389.           drawRadioStationInfo()
  390.         end
  391.       end
  392.     end
  393.   end
  394. end
  395.  
  396. term.setBackgroundColor(colors.black)
  397. term.setTextColor(colors.white)
  398. term.clear()
  399. if not os.getComputerLabel() then os.setComputerLabel("ccTuner") end
  400. if not term.isColor() or pocket or turtle then error("Advanced Computer Required!", 0) end
  401. fm = peripheral.find("openfm_radio")
  402. if not fm then error("No OpenFM tuner found!", 0) end
  403. radioVolume = math.floor(fm.getVol() * 10)
  404. if fs.exists(stationList) then
  405.   for i = #radioStations, 1, -1 do
  406.     radioStations[i] = nil
  407.   end
  408.   local stationData = fs.open(stationList, "r")
  409.   radioStations = textutils.unserialize(stationData.readAll())
  410.   stationData.close()
  411. end
  412. numPages = math.max(1, math.ceil(#radioStations / numPerPage)) --# paginate radio stations
  413. pageNum = math.min(pageNum, numPages)                          --# ensure pageNum is valid
  414. clearLowerScreen()
  415. drawHeader()
  416. drawTunerScreen()
  417. userInput()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement