From 5741a702e14b7e16d973e9dc050311ed8b481210 Mon Sep 17 00:00:00 2001 From: Commandcracker Date: Sat, 17 Jun 2023 00:47:54 +0200 Subject: [PATCH] Small cleanup --- Makefile | 2 +- src/lib/argparse.lua | 6 +- src/lib/youcubeapi.lua | 152 ++++++++------- src/youcube.lua | 425 +++++++++++++++++++++-------------------- stylua.toml | 1 + 5 files changed, 303 insertions(+), 283 deletions(-) create mode 100644 stylua.toml diff --git a/Makefile b/Makefile index 6801200..87d3dc9 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ run: $(CRAFTOS) \ --id 2828 \ --exec "shell.run('clear')shell.run('youcube')" \ - --mount-ro \=.\src + --mount-ro /=./src illuaminate-lint: illuaminate lint diff --git a/src/lib/argparse.lua b/src/lib/argparse.lua index e3694ec..5a86d96 100644 --- a/src/lib/argparse.lua +++ b/src/lib/argparse.lua @@ -151,8 +151,8 @@ local function Do(Lo,Uo)local Co={}for Mo,Fo in ipairs(Lo)do local Wo=jo(Fo,Uo)for Mo,Yo in ipairs(Wo)do table.insert(Co,Yo)end end return Co end function pt:_get_element_help(Po)local Vo=Po:_get_label_lines()local Bo=bo(Po:_get_description())local Go={}local -Ko=self:_inherit_property("help_usage_margin",3)local Qo=(" "):rep(Ko)local -Jo=self:_inherit_property("help_description_margin",25)local +Ko=self:_inherit_property("help_usage_margin",1)local Qo=(" "):rep(Ko)local +Jo=self:_inherit_property("help_description_margin",23)local Xo=(" "):rep(Jo)local Zo=self:_inherit_property("help_max_width")if Zo then local ei=math.max(Zo-Jo,10)Bo=Do(Bo,ei)end if#Vo[1]>=(Jo-Ko)then for ti,ai in ipairs(Vo)do table.insert(Go,Qo..ai)end for oi,ii in ipairs(Bo)do @@ -472,6 +472,6 @@ tostring(jr).."\noriginal "..debug.traceback("",2):sub(2)end function pt:pparse(xr)local zr local Er,Tr=xpcall(function()return self:_parse(xr,function(Ar,Or)zr=Or error(Or,0)end)end,qr)if Er then return true,Tr elseif not zr then error(Tr,0)else return false,zr end end local -Ir={}Ir.version="0.7.2"setmetatable(Ir,{__call=function(Nr,...)return +Ir={}Ir.version="0.7.3"setmetatable(Ir,{__call=function(Nr,...)return pt(vr[0]):add_help(true)(...)end})return Ir \ No newline at end of file diff --git a/src/lib/youcubeapi.lua b/src/lib/youcubeapi.lua index e638331..dd1f9f8 100644 --- a/src/lib/youcubeapi.lua +++ b/src/lib/youcubeapi.lua @@ -35,7 +35,7 @@ local servers = { "ws://127.0.0.1:5000", -- Your server! "wss://yc.tweaked-programs.cc", -- by Sammy#5900 "wss://youcube.knijn.one", -- By EmmaKnijn#0043 - "wss://youcube.onrender.com" -- By Commandcracker#8528 + "wss://youcube.onrender.com", -- By Commandcracker#8528 } if settings then @@ -75,10 +75,12 @@ end --- Connects to a YouCub Server function API:detect_bestest_server(_server, _verbose) + if _server then + table.insert(servers, 1, _server) + end - if _server then table.insert(servers, 1, _server) end - - for i, server in pairs(servers) do + for i = 1, #servers do + local server = servers[i] local ok, err = http.checkURL(server:gsub("^ws://", "http://"):gsub("^wss://", "https://")) if ok then @@ -111,9 +113,7 @@ end -- @tparam string filter action filter -- @treturn table retval data function API:receive(filter) - local status, retval = pcall( - self.websocket.receive - ) + local status, retval = pcall(self.websocket.receive) if not status then error("Lost connection to server\n" .. retval) end @@ -145,10 +145,7 @@ end --- Send data to The YouCub Server -- @tparam table data data to send function API:send(data) - local status, retval = pcall( - self.websocket.send, - textutils.serialiseJSON(data) - ) + local status, retval = pcall(self.websocket.send, textutils.serialiseJSON(data)) if not status then error("Lost connection to server\n" .. retval) end @@ -167,21 +164,29 @@ local b64str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ -- @treturn string string decoded string function Base64.decode(str) local retval = "" - for s in str:gmatch "...." do - if s:sub(3, 4) == '==' then - retval = retval .. - string.char(bit32.bor(bit32.lshift(b64str:find(s:sub(1, 1)) - 1, 2), - bit32.rshift(b64str:find(s:sub(2, 2)) - 1, 4))) - elseif s:sub(4, 4) == '=' then - local n = (b64str:find(s:sub(1, 1)) - 1) * 4096 + (b64str:find(s:sub(2, 2)) - 1) * 64 + - (b64str:find(s:sub(3, 3)) - 1) + for s in str:gmatch("....") do + if s:sub(3, 4) == "==" then + retval = retval + .. string.char( + bit32.bor( + bit32.lshift(b64str:find(s:sub(1, 1)) - 1, 2), + bit32.rshift(b64str:find(s:sub(2, 2)) - 1, 4) + ) + ) + elseif s:sub(4, 4) == "=" then + local n = (b64str:find(s:sub(1, 1)) - 1) * 4096 + + (b64str:find(s:sub(2, 2)) - 1) * 64 + + (b64str:find(s:sub(3, 3)) - 1) retval = retval .. string.char(bit32.extract(n, 10, 8)) .. string.char(bit32.extract(n, 2, 8)) else - local n = (b64str:find(s:sub(1, 1)) - 1) * 262144 + (b64str:find(s:sub(2, 2)) - 1) * 4096 + - (b64str:find(s:sub(3, 3)) - 1) * 64 + (b64str:find(s:sub(4, 4)) - 1) - retval = retval .. - string.char(bit32.extract(n, 16, 8)) .. - string.char(bit32.extract(n, 8, 8)) .. string.char(bit32.extract(n, 0, 8)) + local n = (b64str:find(s:sub(1, 1)) - 1) * 262144 + + (b64str:find(s:sub(2, 2)) - 1) * 4096 + + (b64str:find(s:sub(3, 3)) - 1) * 64 + + (b64str:find(s:sub(4, 4)) - 1) + retval = retval + .. string.char(bit32.extract(n, 16, 8)) + .. string.char(bit32.extract(n, 8, 8)) + .. string.char(bit32.extract(n, 0, 8)) end end return retval @@ -193,9 +198,9 @@ end -- @treturn bytes chunk `16 * 1024` bit chunk function API:get_chunk(chunkindex, id) self:send({ - ["action"] = "get_chunk", + ["action"] = "get_chunk", ["chunkindex"] = chunkindex, - ["id"] = id + ["id"] = id, }) return Base64.decode(self:receive("chunk").chunk) end @@ -208,11 +213,11 @@ end -- @treturn string line one line of the given 32vid function API:get_vid(tracker, id, width, height) self:send({ - ["action"] = "get_vid", + ["action"] = "get_vid", ["tracker"] = tracker, - ["id"] = id, - ["width"] = width * 2, - ["height"] = height * 3 + ["id"] = id, + ["width"] = width * 2, + ["height"] = height * 3, }) return self:receive("vid") end @@ -223,10 +228,10 @@ end function API:request_media(url, width, height) local request = { ["action"] = "request_media", - ["url"] = url + ["url"] = url, } if width and height then - request.width = width * 2 + request.width = width * 2 request.height = height * 3 end self:send(request) @@ -237,7 +242,7 @@ end --@treturn table json response function API:handshake() self:send({ - ["action"] = "handshake" + ["action"] = "handshake", }) return self:receive("handshake") end @@ -290,7 +295,7 @@ end -- @tparam speaker speaker The speaker -- @treturn AudioDevice|Speaker instance function Speaker.new(speaker) - local self = AudioDevice.new { speaker = speaker } + local self = AudioDevice.new({ speaker = speaker }) function self:validate() if not decoder then @@ -326,7 +331,7 @@ local Tape = {} -- @tparam tape tape The tape_drive -- @treturn AudioDevice|Tape instance function Tape.new(tape) - local self = AudioDevice.new { tape = tape } + local self = AudioDevice.new({ tape = tape }) function self:validate() if not self.tape.isReady() then @@ -396,9 +401,9 @@ local AudioFiller = {} -- @treturn AudioFiller|Filler instance function AudioFiller.new(youcubeapi, id) local self = { - id = id, + id = id, chunkindex = 0, - youcubeapi = youcubeapi + youcubeapi = youcubeapi, } function self:next() @@ -423,17 +428,17 @@ local VideoFiller = {} -- @treturn VideoFiller|Filler instance function VideoFiller.new(youcubeapi, id, width, height) local self = { - id = id, - width = width, - height = height, - tracker = 0, - youcubeapi = youcubeapi + id = id, + width = width, + height = height, + tracker = 0, + youcubeapi = youcubeapi, } function self:next() local response = self.youcubeapi:get_vid(self.tracker, self.id, self.width, self.height) - for _, line in pairs(response.lines) do - self.tracker = self.tracker + #line + 1 + for i = 1, #response.lines do + self.tracker = self.tracker + #response.lines[i] + 1 end return response.lines end @@ -453,12 +458,14 @@ local Buffer = {} function Buffer.new(filler, size) local self = { filler = filler, - size = size + size = size, } self.buffer = {} function self:next() - while #self.buffer == 0 do os.pullEvent() end -- Wait until next is available + while #self.buffer == 0 do + os.pullEvent() + end -- Wait until next is available local next = self.buffer[1] table.remove(self.buffer, 1) return next @@ -468,11 +475,11 @@ function Buffer.new(filler, size) if #self.buffer < self.size then local next = filler:next() if type(next) == "table" then - for _, line in pairs(next) do - table.insert(self.buffer, line) + for i = 1, #next do + self.buffer[#self.buffer + 1] = next[i] end else - table.insert(self.buffer, next) + self.buffer[#self.buffer + 1] = next end return true end @@ -486,17 +493,12 @@ local currnt_palette = {} for i = 0, 15 do local r, g, b = term.getPaletteColour(2 ^ i) - currnt_palette[i] = {r, g, b} + currnt_palette[i] = { r, g, b } end local function reset_term() for i = 0, 15 do - term.setPaletteColor( - 2 ^ i, - currnt_palette[i][1], - currnt_palette[i][2], - currnt_palette[i][3] - ) + term.setPaletteColor(2 ^ i, currnt_palette[i][1], currnt_palette[i][2], currnt_palette[i][3]) end term.setBackgroundColor(colors.black) term.setTextColor(colors.white) @@ -522,7 +524,9 @@ local function play_vid(buffer, force_fps, string_unpack) end local fps = tonumber(buffer:next()) - if force_fps then fps = force_fps end + if force_fps then + fps = force_fps + end -- Adjust buffer size buffer.size = math.ceil(fps) * 2 @@ -534,7 +538,7 @@ local function play_vid(buffer, force_fps, string_unpack) end term.clear() - local start = os.epoch "utc" + local start = os.epoch("utc") local frame_count = 0 while true do frame_count = frame_count + 1 @@ -600,7 +604,9 @@ local function play_vid(buffer, force_fps, string_unpack) read() break else - while os.epoch "utc" < start + (frame_count + 1) / fps * 1000 do sleep(1 / fps) end + while os.epoch("utc") < start + (frame_count + 1) / fps * 1000 do + sleep(1 / fps) + end end end reset_term() @@ -610,22 +616,22 @@ return { --- "Metadata" - [YouCube API](https://commandcracker.github.io/YouCube/) Version _API_VERSION = "0.0.0-poc.1.0.0", --- "Metadata" - Library Version - _VERSION = "0.0.0-poc.1.4.0", + _VERSION = "0.0.0-poc.1.4.1", --- "Metadata" - Description _DESCRIPTION = "Library for accessing YouCub's API", --- "Metadata" - Homepage / Url - _URL = "https://github.com/Commandcracker/YouCube", + _URL = "https://github.com/Commandcracker/YouCube", --- "Metadata" - License - _LICENSE = "GPL-3.0", - API = API, - AudioDevice = AudioDevice, - Speaker = Speaker, - Tape = Tape, - Base64 = Base64, - Filler = Filler, - AudioFiller = AudioFiller, - VideoFiller = VideoFiller, - Buffer = Buffer, - play_vid = play_vid, - reset_term = reset_term + _LICENSE = "GPL-3.0", + API = API, + AudioDevice = AudioDevice, + Speaker = Speaker, + Tape = Tape, + Base64 = Base64, + Filler = Filler, + AudioFiller = AudioFiller, + VideoFiller = VideoFiller, + Buffer = Buffer, + play_vid = play_vid, + reset_term = reset_term, } diff --git a/src/youcube.lua b/src/youcube.lua index 1f338bb..9ee6906 100644 --- a/src/youcube.lua +++ b/src/youcube.lua @@ -7,17 +7,18 @@ Github Repository: https://github.com/Commandcracker/YouCube License: GPL-3.0 ]] -local _VERSION = "0.0.0-poc.1.1.0" +local _VERSION = "0.0.0-poc.1.1.1" --- Libraries - OpenLibrarieLoader v1.0.0 -- +-- Libraries - OpenLibrarieLoader v1.0.1 -- --TODO: Optional libs: -- For something like a JSON lib that is only needed for older CC Versions or -- optional logging.lua support -local function is_lib(Table, Item) - for key, value in ipairs(Table) do - if value == Item or value .. ".lua" == Item then +local function is_lib(libs, lib) + for i = 1, #libs do + local value = libs[i] + if value == lib or value .. ".lua" == lib then return true, value end end @@ -27,45 +28,52 @@ end local libs = { "youcubeapi", "numberformatter", "semver", "argparse", "string_pack" } local lib_paths = { ".", "./lib", "./apis", "./modules", "/", "/lib", "/apis", "/modules" } +-- LevelOS Support if _G.lOS then - table.insert(lib_paths, "/Program_Files/YouCube/lib") + lib_paths[#lib_paths + 1] = "/Program_Files/YouCube/lib" end -for i, path in pairs(lib_paths) do +local function load_lib(lib) + if require then + return require(lib:gsub(".lua", "")) + end + return dofile(lib) +end + +for i_path = 1, #lib_paths do + local path = lib_paths[i_path] if fs.exists(path) then - for _i, file_name in pairs(fs.list(path)) do - local found, lib = is_lib(libs, file_name) - if found and libs[lib] == nil then - if require then - libs[lib] = require(path .. "/" .. file_name:gsub(".lua", "")) - else - libs[lib] = dofile(path .. "/" .. file_name) - end + local files = fs.list(path) + for i_file = 1, #files do + local found, lib = is_lib(libs, files[i_file]) + if found and lib ~= nil and libs[lib] == nil then + libs[lib] = load_lib(path .. "/" .. files[i_file]) end end end end -for key, lib in ipairs(libs) do +for i = 1, #libs do + local lib = libs[i] if libs[lib] == nil then - error("Library \"" .. lib .. "\" not found") + error(('Library "%s" not found.'):format(lib)) end end -- args -- -local program_name -if arg then - program_name = arg[0] -else - program_name = fs.getName(shell.getRunningProgram()):gsub("[\\.].*$", "") +local function get_program_name() + if arg then + return arg[0] + end + return fs.getName(shell.getRunningProgram()):gsub("[\\.].*$", "") end +-- stylua: ignore start + local parser = libs.argparse { help_max_width = ({ term.getSize() })[1], - help_usage_margin = 1, - help_description_margin = 23, - name = program_name + name = get_program_name() } :description "Official YouCube client for accessing media from services like YouTube" @@ -116,7 +124,9 @@ parser:option "--fps" :description "Force sanjuuni to use a specified frame rate" :target "force_fps" -local args = parser:parse { ... } +-- stylua: ignore end + +local args = parser:parse({ ... }) if args.force_fps then args.force_fps = tonumber(args.force_fps) @@ -156,43 +166,51 @@ if periphemu then config.set("http_max_websocket_message", 2 ^ 30) end --- main -- - -local speakers = { peripheral.find("speaker") } -local tapes = { peripheral.find("tape_drive") } - -if #speakers == 0 and #tapes == 0 then - error("You need a tapedrive or speaker in order to use YouCube!") -end +local function get_audiodevices() + local audiodevices = {} -local youcubeapi = libs.youcubeapi.API.new() + local speakers = { peripheral.find("speaker") } + for i = 1, #speakers do + audiodevices[#audiodevices + 1] = libs.youcubeapi.Speaker.new(speakers[i]) + end -local audiodevices = {} + local tapes = { peripheral.find("tape_drive") } + for i = 1, #tapes do + audiodevices[#audiodevices + 1] = libs.youcubeapi.Tape.new(tapes[i]) + end -for _, speaker in pairs(speakers) do - table.insert(audiodevices, libs.youcubeapi.Speaker.new(speaker)) -end + if #audiodevices == 0 then + -- Disable audio when no audiodevice is found + args.no_audio = true + return audiodevices + end -for _, tape in pairs(tapes) do - table.insert(audiodevices, libs.youcubeapi.Tape.new(tape)) -end + -- Validate audiodevices + local last_error + local valid_audiodevices = {} -local last_error -local valid_audiodevices = {} + for i = 1, #audiodevices do + local audiodevice = audiodevices[i] + local _error = audiodevice:validate() + if _error == nil then + valid_audiodevices[#valid_audiodevices + 1] = audiodevice + else + last_error = _error + end + end -for i, audiodevice in pairs(audiodevices) do - local _error = audiodevice:validate() - if _error ~= nil then - last_error = _error - else - table.insert(valid_audiodevices, audiodevice) + if #valid_audiodevices == 0 then + error(last_error) end -end -if #valid_audiodevices == 0 then - error(last_error) + return valid_audiodevices end +-- main -- + +local youcubeapi = libs.youcubeapi.API.new() +local audiodevices = get_audiodevices() + -- update check -- local function get_versions() @@ -201,13 +219,13 @@ local function get_versions() -- Check if the URL is valid local ok, err = http.checkURL(url) if not ok then - printError("Invalid Update URL.", "\"" .. url .. "\" ", err) + printError("Invalid Update URL.", '"' .. url .. '" ', err) return end local response, http_err = http.get(url, nil, true) if not response then - printError("Failed to retreat data from update URL. \"" .. url .. "\" (" .. http_err .. ")") + printError('Failed to retreat data from update URL. "' .. url .. '" (' .. http_err .. ")") return end @@ -217,6 +235,22 @@ local function get_versions() return textutils.unserialiseJSON(sResponse) end +local function write_colored(text, color) + term.setTextColor(color) + term.write(text) +end + +local function new_line() + local w, h = term.getSize() + local x, y = term.getCursorPos() + if y + 1 <= h then + term.setCursorPos(1, y + 1) + else + term.setCursorPos(1, h) + term.scroll(1) + end +end + local function write_outdated(current, latest) if libs.semver(current) ^ libs.semver(latest) then term.setTextColor(colors.yellow) @@ -225,87 +259,61 @@ local function write_outdated(current, latest) end term.write(current) - term.setTextColor(colors.lightGray) - term.write(" -> ") - term.setTextColor(colors.lime) - term.write(latest) + write_colored(" -> ", colors.lightGray) + write_colored(latest, colors.lime) term.setTextColor(colors.white) + new_line() end local function can_update(name, current, latest) if libs.semver(current) < libs.semver(latest) then term.write(name .. " ") - write_outdated(current, latest) - print() end end local function update_checker() local versions = get_versions() - if versions == nil then return end + if versions == nil then + return + end - can_update( - "youcube", - _VERSION, - versions.client.version - ) - can_update( - "youcubeapi", - libs.youcubeapi._VERSION, - versions.client.libraries.youcubeapi.version - ) - can_update( - "numberformatter", - libs.numberformatter._VERSION, - versions.client.libraries.numberformatter.version - ) - can_update( - "semver", - tostring(libs.semver._VERSION), - versions.client.libraries.semver.version - ) - can_update( - "argparse", - libs.argparse.version, - versions.client.libraries.argparse.version - ) + can_update("youcube", _VERSION, versions.client.version) + can_update("youcubeapi", libs.youcubeapi._VERSION, versions.client.libraries.youcubeapi.version) + can_update("numberformatter", libs.numberformatter._VERSION, versions.client.libraries.numberformatter.version) + can_update("semver", tostring(libs.semver._VERSION), versions.client.libraries.semver.version) + can_update("argparse", libs.argparse.version, versions.client.libraries.argparse.version) local handshake = youcubeapi:handshake() if libs.semver(handshake.server.version) < libs.semver(versions.server.version) then print("Tell the server owner to update their server!") write_outdated(handshake.server.version, versions.server.version) - print() end if not libs.semver(libs.youcubeapi._API_VERSION) ^ libs.semver(handshake.api.version) then print("Client is not compatible with server") - term.setTextColor(colors.red) - term.write(libs.youcubeapi._API_VERSION) - term.setTextColor(colors.lightGray) - term.write(" ^ ") - term.setTextColor(colors.red) - term.write(handshake.api.version) + write_colored(libs.youcubeapi._API_VERSION, colors.red) + write_colored(" ^ ", colors.lightGray) + write_colored(handshake.api.version, colors.red) term.setTextColor(colors.white) - print() + new_line() end if libs.semver(libs.youcubeapi._API_VERSION) < libs.semver(versions.api.version) then print("Your client is using an outdated API version") write_outdated(libs.youcubeapi._API_VERSION, versions.api.version) - print() end if libs.semver(handshake.api.version) < libs.semver(versions.api.version) then print("The server is using an outdated API version") write_outdated(libs.youcubeapi._API_VERSION, versions.api.version) - print() end end local function play_audio(buffer, title) - for _, audiodevice in pairs(valid_audiodevices) do + for i = 1, #audiodevices do + local audiodevice = audiodevices[i] audiodevice:reset() audiodevice:setLabel(title) audiodevice:setVolume(args.volume) @@ -321,10 +329,11 @@ local function play_audio(buffer, title) if chunk == "" then local play_functions = {} - for _, audiodevice in pairs(valid_audiodevices) do - table.insert(play_functions, function() + for i = 1, #audiodevices do + local audiodevice = audiodevices[i] + play_functions[#play_functions + 1] = function() audiodevice:play() - end) + end end parallel.waitForAll(table.unpack(play_functions)) @@ -332,7 +341,8 @@ local function play_audio(buffer, title) end local write_functions = {} - for _, audiodevice in pairs(valid_audiodevices) do + for i = 1, #audiodevices do + local audiodevice = audiodevices[i] table.insert(write_functions, function() audiodevice:write(chunk) end) @@ -349,6 +359,11 @@ local queue = {} local restart = false -- #endregion +-- keys +local skip_key = settings.get("youcube.keys.skip") or keys.d +local restart_key = settings.get("youcube.keys.restart") or keys.r +local back_key = settings.get("youcube.keys.back") or keys.a + local function play(url) restart = false print("Requesting media ...") @@ -365,15 +380,14 @@ local function play(url) repeat data = youcubeapi:receive() if data.action == "status" then + os.queueEvent("youcube:status", data) term.setCursorPos(x, y) term.clearLine() term.write("Status: ") - term.setTextColor(colors.green) - os.queueEvent("youcube:status", data) - term.write(data.message) + write_colored(data.message, colors.green) term.setTextColor(colors.white) else - print() + new_line() end until data.action == "media" @@ -400,22 +414,12 @@ local function play(url) end local video_buffer = libs.youcubeapi.Buffer.new( - libs.youcubeapi.VideoFiller.new( - youcubeapi, - data.id, - term.getSize() - ), - --[[ - Most videos run on 30 fps, so we store 2s of video. - ]] - 60 + libs.youcubeapi.VideoFiller.new(youcubeapi, data.id, term.getSize()), + 60 -- Most videos run on 30 fps, so we store 2s of video. ) local audio_buffer = libs.youcubeapi.Buffer.new( - libs.youcubeapi.AudioFiller.new( - youcubeapi, - data.id - ), + libs.youcubeapi.AudioFiller.new(youcubeapi, data.id), --[[ We want to buffer 1024 chunks. One chunks is 16 bits. @@ -430,119 +434,128 @@ local function play(url) term.write("[DEBUG MODE]") end - parallel.waitForAny( - function() - -- Fill Buffers - while true do - os.queueEvent("youcube:fill_buffers") + local function fill_buffers() + while true do + os.queueEvent("youcube:fill_buffers") - local event = os.pullEventRaw() + local event = os.pullEventRaw() - if event == "terminate" then - libs.youcubeapi.reset_term() - end + if event == "terminate" then + libs.youcubeapi.reset_term() + end - if not args.no_audio then - audio_buffer:fill() - end + if not args.no_audio then + audio_buffer:fill() + end - if args.verbose then - term.setCursorPos(1, ({ term.getSize() })[2]) - term.clearLine() - term.write("Audio_Buffer: " .. #audio_buffer.buffer) - end + if args.verbose then + term.setCursorPos(1, ({ term.getSize() })[2]) + term.clearLine() + term.write("Audio_Buffer: " .. #audio_buffer.buffer) + end + + if not args.no_video then + video_buffer:fill() + end + end + end + + local function _play_video() + if not args.no_video then + local string_unpack + if not string.unpack then + string_unpack = libs.string_pack.unpack + end + + os.queueEvent("youcube:vid_playing", data) + libs.youcubeapi.play_vid(video_buffer, args.force_fps, string_unpack) + os.queueEvent("youcube:vid_eof", data) + end + end + + local function _play_audio() + if not args.no_audio then + os.queueEvent("youcube:audio_playing", data) + play_audio(audio_buffer, data.title) + os.queueEvent("youcube:audio_eof", data) + end + end + + local function _play_media() + os.queueEvent("youcube:playing") + parallel.waitForAll(_play_video, _play_audio) + end + local function _hotkey_handler() + while true do + local _, key = os.pullEvent("key") + + if key == skip_key then + back_buffer[#back_buffer + 1] = url --finished playing, push the value to the back buffer + if #back_buffer > max_back then + back_buffer[1] = nil --remove it from the front of the buffer + end if not args.no_video then - video_buffer:fill() + libs.youcubeapi.reset_term() end + break end - end, - function() - os.queueEvent("youcube:playing") - parallel.waitForAll( - function() - if not args.no_video then - local string_unpack - if not string.unpack then - string_unpack = libs.string_pack.unpack - end - - os.queueEvent("youcube:vid_playing", data) - libs.youcubeapi.play_vid(video_buffer, args.force_fps, string_unpack) - os.queueEvent("youcube:vid_eof", data) - end - end, - function() - if not args.no_audio then - os.queueEvent("youcube:audio_playing", data) - play_audio(audio_buffer, data.title) - os.queueEvent("youcube:audio_eof", data) - end - end - ) - end, - function() - while true do - local _, key = os.pullEvent("key") - if key == (settings.get("youcube.keys.skip") or keys.d) then - table.insert(back_buffer, url) --finished playing, push the value to the back buffer - if #back_buffer > max_back then - table.remove(back_buffer, 1) --remove it from the front of the buffer - end - if not args.no_video then - libs.youcubeapi.reset_term() - end - break - elseif key == (settings.get("youcube.keys.restart") or keys.r) then - table.insert(queue, url) --add the current song to upcoming - if not args.no_video then - libs.youcubeapi.reset_term() - end - restart = true - break + + if key == restart_key then + queue[#queue + 1] = url --add the current song to upcoming + if not args.no_video then + libs.youcubeapi.reset_term() end + restart = true + break end end - ) + end + + parallel.waitForAny(fill_buffers, _play_media, _hotkey_handler) if data.playlist_videos then return data.playlist_videos end end +local function shuffle_playlist(playlist) + local shuffled = {} + for i = 1, #queue do + local pos = math.random(1, #shuffled + 1) + shuffled[pos] = queue[i] + end + return shuffled +end + local function play_playlist(playlist) queue = playlist if args.shuffle then - local shuffled = {} - for i, v in pairs(queue) do - local pos = math.random(1, #shuffled + 1) - table.insert(shuffled, pos, v) - end - queue = shuffled + queue = shuffle_playlist(queue) end while #queue ~= 0 do local pl = table.remove(queue) - parallel.waitForAny( - function() - while true do - local _, key = os.pullEvent("key") - if key == (settings.get("youcube.keys.back") or keys.a) then - table.insert(queue, pl) --add the current song to upcoming - local prev = table.remove(back_buffer) - if prev then --nil/false check - table.insert(queue, prev) --add previous song to upcoming - end - if not args.no_video then - libs.youcubeapi.reset_term() - end - break + + local function handle_back_hotkey() + while true do + local _, key = os.pullEvent("key") + if key == back_key then + queue[#queue + 1] = pl --add the current song to upcoming + local prev = table.remove(back_buffer) + if prev then --nil/false check + queue[#queue + 1] = prev --add previous song to upcoming + end + if not args.no_video then + libs.youcubeapi.reset_term() end + break end - end, - function() - play(pl) --play the url end - ) + end + + parallel.waitForAny(handle_back_hotkey, function() + play(pl) --play the url + end) end end diff --git a/stylua.toml b/stylua.toml new file mode 100644 index 0000000..394e884 --- /dev/null +++ b/stylua.toml @@ -0,0 +1 @@ +indent_type = "Spaces"