2023-10-17 15:28:43 +03:00
|
|
|
local drive = peripheral.find("tape_drive")
|
2023-10-17 15:32:35 +03:00
|
|
|
if not drive then
|
2023-10-17 15:28:43 +03:00
|
|
|
printError("no tape drive found")
|
|
|
|
printError("it's kinda required to play tapes, you know?")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local running = true
|
|
|
|
|
2023-10-17 20:01:54 +03:00
|
|
|
term.setBackgroundColor(colors.black)
|
2023-10-17 19:54:57 +03:00
|
|
|
term.clear()
|
|
|
|
local screen_w, screen_h = term.getSize()
|
2023-10-17 15:28:43 +03:00
|
|
|
local table_of_contents = {}
|
|
|
|
|
2023-10-17 19:54:57 +03:00
|
|
|
|
2023-10-17 15:28:43 +03:00
|
|
|
local function read32()
|
|
|
|
local v = 0
|
|
|
|
for i = 1, 4 do
|
|
|
|
local b = drive.read()
|
2023-10-17 15:33:15 +03:00
|
|
|
v = bit32.bor(bit32.lshift(v, 8), b)
|
2023-10-17 15:28:43 +03:00
|
|
|
end
|
|
|
|
return v
|
|
|
|
end
|
|
|
|
|
|
|
|
local function bytes2time(b)
|
|
|
|
local s = math.floor(b / 6000)
|
|
|
|
if s < 60 then return string.format("%ds", s) end
|
|
|
|
return string.format("%dm, %ds", math.floor(s / 60), s % 60)
|
|
|
|
end
|
|
|
|
|
2023-10-17 19:54:57 +03:00
|
|
|
local function textProgress(p, c1, c2, fmt, ...)
|
|
|
|
local tw = term.getSize()
|
|
|
|
local str = string.format(fmt, ...)
|
|
|
|
local w1 = math.ceil(p * tw)
|
|
|
|
local w2 = tw - w1
|
|
|
|
|
|
|
|
local bg = term.getBackgroundColor()
|
2023-10-17 20:01:54 +03:00
|
|
|
|
2023-10-17 19:54:57 +03:00
|
|
|
term.setBackgroundColor(c1)
|
|
|
|
term.write(str:sub(1, w1))
|
|
|
|
local rem = w1 - #str
|
|
|
|
if rem > 0 then
|
|
|
|
term.write(string.rep(" ", rem))
|
|
|
|
end
|
|
|
|
|
|
|
|
term.setBackgroundColor(c2)
|
|
|
|
term.write(str:sub(w1 + 1, w1 + w2))
|
|
|
|
|
|
|
|
rem = math.min(tw - #str, w2)
|
|
|
|
if rem > 0 then
|
|
|
|
term.write(string.rep(" ", rem))
|
|
|
|
end
|
|
|
|
|
|
|
|
term.setBackgroundColor(bg)
|
|
|
|
end
|
|
|
|
|
2023-10-17 15:28:43 +03:00
|
|
|
|
|
|
|
parallel.waitForAll(
|
|
|
|
function()
|
|
|
|
while running do
|
2023-10-17 19:54:57 +03:00
|
|
|
if drive.isReady() then
|
|
|
|
local pos, size = drive.getPosition(), drive.getSize()
|
|
|
|
for i = 1, math.min(screen_h - 2, 48) do
|
|
|
|
term.setCursorPos(1, i)
|
|
|
|
local song = table_of_contents[i]
|
|
|
|
if song then
|
|
|
|
local is_playing = pos >= song.offset and pos < song.ending
|
|
|
|
local s = string.format("#%2d %9s %s", i, bytes2time(song.length), song.title)
|
|
|
|
if is_playing then
|
|
|
|
local p = (pos - song.offset) / song.length
|
|
|
|
textProgress(p, colors.lime, colors.lightGray, s)
|
|
|
|
else
|
|
|
|
term.setBackgroundColor(i % 2 == 0 and colors.gray or colors.black)
|
2023-10-17 20:01:54 +03:00
|
|
|
term.clearLine()
|
2023-10-17 19:54:57 +03:00
|
|
|
term.write(s)
|
|
|
|
end
|
|
|
|
end
|
2023-10-17 16:16:02 +03:00
|
|
|
end
|
2023-10-17 20:01:54 +03:00
|
|
|
|
2023-10-17 19:54:57 +03:00
|
|
|
term.setCursorPos(1, screen_h)
|
|
|
|
textProgress(pos / size, colors.red, colors.gray, "%8d / %8d [%s]", pos, size, drive.getState())
|
2023-10-17 16:16:02 +03:00
|
|
|
end
|
2023-10-17 15:28:43 +03:00
|
|
|
os.sleep(0.1)
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
function()
|
|
|
|
while running do
|
|
|
|
local evd = { os.pullEvent() }
|
|
|
|
local ev, evd = table.remove(evd, 1), evd
|
|
|
|
|
|
|
|
if ev == "mouse_click" then
|
2023-10-17 16:30:18 +03:00
|
|
|
local x, y = table.unpack(evd, 2)
|
2023-10-17 16:26:53 +03:00
|
|
|
if drive.isReady() and y <= #table_of_contents then
|
|
|
|
drive.seek(-drive.getSize())
|
2023-10-17 16:29:23 +03:00
|
|
|
drive.seek(table_of_contents[y].offset)
|
2023-10-17 16:26:53 +03:00
|
|
|
drive.play()
|
|
|
|
end
|
2023-10-17 16:16:02 +03:00
|
|
|
elseif ev == "term_resize" then
|
2023-10-17 20:01:54 +03:00
|
|
|
term.setBackgroundColor(colors.black)
|
2023-10-17 18:26:18 +03:00
|
|
|
term.clear()
|
2023-10-17 16:16:02 +03:00
|
|
|
screen_w, screen_h = term.getSize()
|
2023-10-17 15:28:43 +03:00
|
|
|
elseif ev == "tape_present" then
|
|
|
|
table_of_contents = {}
|
2023-10-17 20:03:10 +03:00
|
|
|
term.clear()
|
2023-10-17 15:28:43 +03:00
|
|
|
if evd[1] then
|
2023-10-17 15:45:22 +03:00
|
|
|
drive.stop()
|
2023-10-17 15:28:43 +03:00
|
|
|
drive.seek(-drive.getSize())
|
|
|
|
for i = 1, 48 do
|
|
|
|
local offset = read32()
|
|
|
|
local length = read32()
|
2023-10-17 16:20:16 +03:00
|
|
|
local title = drive.read(117):gsub("\x00", "")
|
|
|
|
if length > 0 then
|
|
|
|
table.insert(table_of_contents, {
|
|
|
|
title = title,
|
|
|
|
offset = offset,
|
|
|
|
length = length,
|
|
|
|
ending = offset + length
|
|
|
|
})
|
|
|
|
end
|
2023-10-17 15:28:43 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
function()
|
|
|
|
local tape_was_present = nil
|
|
|
|
local drive_old_state = nil
|
|
|
|
while running do
|
|
|
|
local tape_present = drive.isReady()
|
|
|
|
if tape_present ~= tape_was_present then
|
|
|
|
os.queueEvent("tape_present", tape_present)
|
2023-10-17 16:07:54 +03:00
|
|
|
tape_was_present = tape_present
|
2023-10-17 15:28:43 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
local drive_state = drive.getState()
|
|
|
|
if drive_old_state ~= drive_state then
|
|
|
|
os.queueEvent("drive_state", drive_state)
|
2023-10-17 16:07:54 +03:00
|
|
|
drive_old_state = drive_state
|
2023-10-17 15:28:43 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
os.sleep(0.25)
|
|
|
|
end
|
|
|
|
end)
|