forked from hkc/cc-stuff
1
0
Fork 0
cc-stuff/mess/tmpc.lua

488 lines
17 KiB
Lua
Raw Normal View History

2023-10-19 20:27:14 +03:00
settings.define("mplayer.colors.bg", {
description = "Background color in media player",
default = 0x131313, -- #131313
type = number
})
settings.define("mplayer.colors.fg", {
description = "Text color in media player",
default = 0xEFEFEF, -- #EFEFEF
type = number
})
settings.define("mplayer.colors.cursor", {
description = "Color of the cursor",
default = 0x8080EF, -- #8080EF
type = number
})
settings.define("mplayer.colors.current", {
description = "Color of the currently playing song",
default = 0xEFEF80, -- #EFEF80
type = number
})
settings.define("mplayer.colors.status", {
description = "Color of the statusbar",
default = 0x80EF80, -- #80EF80
type = number
})
2023-10-20 02:35:02 +03:00
local drive = peripheral.find("tape_drive")
2023-10-20 02:16:46 +03:00
if not drive then
printError("No drive found, starting in dummy mode")
local fp = io.open("noita.dfpwm", "rb")
if fp == nil then
printError("No sample file found, are you running it on a real* computer without a tape drive?")
return
end
local size = fp:seek("end", 0)
fp:seek("set", 0)
2023-10-20 02:16:46 +03:00
drive = {
_pos = 0,
_fp = fp,
_state = "STOPPED",
isDummy = true,
2023-10-20 02:16:46 +03:00
seek = function(howMuch)
drive._pos = math.min(drive.getSize(), math.max(0, drive._pos + howMuch))
end,
getPosition = function()
return drive._pos
end,
read = function(n)
local out = { drive._fp:read(n) }
drive.seek(n or 1)
return table.unpack(out)
end,
2023-10-20 02:16:46 +03:00
getSize = function()
return size
end,
getState = function()
return drive._state
end,
play = function()
drive._state = "PLAYING"
end,
stop = function()
drive._state = "STOPPED"
end,
isReady = function()
return true
2023-10-20 02:16:46 +03:00
end,
_tick = function()
if drive._state == "PLAYING" then
drive.read(600)
end
end,
2023-10-20 02:16:46 +03:00
}
os.sleep(1)
end
local function time2str(ti)
ti = math.floor(ti)
local m, s = math.floor(ti / 60), ti % 60
return string.format("%02d:%02d", m, s)
end
local function read32()
local v = 0
for i = 1, 4 do
local b = string.byte(drive.read(1), 1)
v = bit32.bor(bit32.lshift(v, 8), b)
end
return v
end
local help = {}
for line in ([[# Movement:
--
Up k : Move cursor up
Down j : Move cursor down
H : Move cursor to the top of screen
L : Move cursor to the bottom of screen
PageUp : Page up
PageDown : Page down
Tab : Next screen
Shift+Tab : Previous screen
1 F1 h : Help screen (this one)
2 F2 : Songs list
3 F3 : Options screen
# Global:
--
s : Stop and seek to the beginning
p : Pause/resume
< : Next track
> : Previous track
f : Seek forward
b : Seek backward
Left - : Decrease volume
Right + : Increase volume
# List screen:
--
Enter : Play
Ctrl+l : Center
l : Jump to current track
]]):gmatch("[^\n]+") do
table.insert(help, line)
end
2023-10-19 20:27:14 +03:00
local mplayer = {
colors = {
bg = colors.black,
fg = colors.white,
cursor = colors.blue,
current = colors.yellow,
status = colors.lime
},
heldKeys = {},
screens = {
{
title = "Help",
scroll = 0,
render = function(self)
local tw, th = term.getSize()
for i = 1, th - 3 do
local line = help[i + self.screens[1].scroll] or "~"
term.setCursorPos(1, i + 1)
term.clearLine()
if line:sub(1, 1) == "~" then
term.setTextColor(self.colors.cursor)
elseif line:sub(1, 1) == "#" then
term.setTextColor(self.colors.current)
elseif line:sub(1, 2) == "--" then
term.setTextColor(self.colors.status)
term.write(("-"):rep(tw - 2))
else
term.setTextColor(self.colors.fg)
end
term.write(line)
end
end,
handleKey = function(self, key, repeating)
local _, th = term.getSize()
if key == keys.down or key == keys.j then
self.screens[1].handleScroll(self, 1)
elseif key == keys.up or key == keys.k then
self.screens[1].handleScroll(self, -1)
elseif key == keys.pageDown then
self.screens[1].handleScroll(self, th - 3)
elseif key == keys.pageUp then
self.screens[1].handleScroll(self, -(th - 3))
end
end,
handleScroll = function(self, direction, x, y)
local _, th = term.getSize()
self.screens[1].scroll = math.max(0, math.min(th - 1, self.screens[1].scroll + direction))
end,
},
{
title = "List",
scroll = 0,
cursor = 1,
textScroll = 0,
render = function(self)
local tw, th = term.getSize()
for i = 1, th - 3 do
local song = self.songs[i + self.screens[2].scroll]
local isCurrent = (i + self.screens[2].scroll) == self.currentSong
local isHovered = (i + self.screens[2].scroll) == self.screens[2].cursor
term.setCursorPos(1, i + 1)
local bg, fg = self.colors.bg, (isCurrent and self.colors.current or self.colors.fg)
if isHovered then bg, fg = fg, bg end
term.setBackgroundColor(bg)
term.setTextColor(fg)
term.clearLine()
if song then
local timeString = " ["..time2str(song.length / 6000) .. "]"
local w = tw - #timeString
if #song.title <= w then
term.write(song.title)
else
local off = isHovered and ((self.screens[2].textScroll % (#song.title + 5)) + 1) or 1
local txt = song.title .. " ::: " .. song.title
term.write(txt:sub(off, off + w - 1))
end
term.setCursorPos(tw - #timeString + 1, i + 1)
term.write(timeString)
end
end
end,
handleKey = function(self, key, repeating)
local _, th = term.getSize()
if key == keys.down or key == keys.j then
self.screens[2].handleScroll(self, 1)
elseif key == keys.up or key == keys.k then
self.screens[2].handleScroll(self, -1)
elseif key == keys.pageDown then
self.screens[2].handleScroll(self, th - 3)
elseif key == keys.pageUp then
self.screens[2].handleScroll(self, -(th - 3))
elseif key == keys.enter then
2023-10-20 02:16:46 +03:00
drive.seek(-drive.getSize())
drive.seek(self.songs[self.screens[2].cursor].offset)
drive.play()
self.currentSong = self.screens[2].cursor
end
end,
handleScroll = function(self, direction, x, y)
local _, th = term.getSize()
self.screens[2].cursor = math.max(1, math.min(#self.songs, self.screens[2].cursor + direction))
if self.screens[2].scroll + 1 > self.screens[2].cursor then
self.screens[2].scroll = self.screens[2].cursor - 1
end
local maxi = self.screens[2].scroll + th - 3
if self.screens[2].cursor > maxi then
self.screens[2].scroll = self.screens[2].cursor - (th - 3)
end
self.screens[2].textScroll = 0
end,
},
{
title = "Settings",
scroll = 0,
cursor = 1,
render = function(self)
term.clear()
term.write(string.format("opt = %d, scroll = %d", self.screens[3].cursor, self.screens[3].scroll))
end,
handleKey = function(self, key, repeating)
local _, th = term.getSize()
if key == keys.down or key == keys.j then
self.screens[3].handleScroll(self, 1)
elseif key == keys.up or key == keys.k then
self.screens[3].handleScroll(self, -1)
elseif key == keys.pageDown then
self.screens[3].handleScroll(self, th - 3)
elseif key == keys.pageUp then
self.screens[3].handleScroll(self, -(th - 3))
end
end,
handleScroll = function(self, direction, x, y)
local _, th = term.getSize()
self.screens[3].cursor = math.max(1, math.min(20, self.screens[3].cursor + direction))
if self.screens[3].scroll + 1 > self.screens[3].cursor then
self.screens[3].scroll = self.screens[3].cursor - 1
end
local maxi = self.screens[3].scroll + th - 3
if self.screens[3].cursor > maxi then
self.screens[3].scroll = self.screens[3].cursor - (th - 3)
end
end
}
},
2023-10-19 20:27:14 +03:00
songs = {},
currentSong = 0,
statusLineScroll = 0,
currentScreen = 2,
2023-10-19 20:27:14 +03:00
}
local function setupTerminal()
for k, v in pairs(mplayer.colors) do
term.setPaletteColor(v, settings.get("mplayer.colors." .. k))
end
term.setCursorPos(1, 1)
term.setBackgroundColor(mplayer.colors.bg)
term.setTextColor(mplayer.colors.fg)
term.clear()
end
setupTerminal()
local tw, th = term.getSize()
parallel.waitForAny(
function()
while true do
-- Current screen
term.setCursorPos(1, 2)
mplayer.screens[mplayer.currentScreen].render(mplayer)
2023-10-19 20:27:14 +03:00
-- Top bar
term.setCursorPos(1, 1)
for i, screen in ipairs(mplayer.screens) do
term.setTextColor(mplayer.colors[i == mplayer.currentScreen and "bg" or "fg"])
term.setBackgroundColor(mplayer.colors[i == mplayer.currentScreen and "fg" or "bg"])
term.write(" "..i..":"..screen.title.." ")
2023-10-19 20:27:14 +03:00
end
term.setBackgroundColor(mplayer.colors.bg)
2023-10-20 02:16:46 +03:00
local title, time, duration = "Whatever is on the tape", drive.getPosition() / 6000, drive.getSize() / 6000
2023-10-19 20:27:14 +03:00
if mplayer.currentSong ~= 0 then
local song = mplayer.songs[mplayer.currentSong]
2023-10-20 02:16:46 +03:00
time = (drive.getPosition() - song.offset) / 6000
2023-10-19 20:27:14 +03:00
duration = song.length / 6000
title = song.title
end
-- Statusline
term.setCursorPos(1, th)
term.clearLine()
local timeString = string.format("[%s:%s]", time2str(time), time2str(duration))
if drive.getState() == "PLAYING" then
term.setTextColor(mplayer.colors.status)
term.write("Playing: ") -- 9 characters
2023-10-19 20:27:14 +03:00
-- Progressbar
local lw = math.floor(tw * time / duration)
term.setCursorPos(1, th - 1)
term.setTextColor(mplayer.colors.current)
term.clearLine()
term.write(string.rep("=", lw))
term.write(">")
term.setTextColor(mplayer.colors.cursor)
term.write(string.rep("-", tw - lw - 1))
-- Statusline text
term.setCursorPos(10, th)
local w = tw - #timeString - 10 -- "Playing: " plus extra space
term.setTextColor(mplayer.colors.current)
if #title <= w then
term.write(title)
else
local off = (mplayer.statusLineScroll % (#title + 5)) + 1
local txt = title .. " ::: " .. title
term.write(txt:sub(off, off + w - 1))
end
2023-10-19 20:27:14 +03:00
end
term.setTextColor(mplayer.colors.status)
term.setCursorPos(tw - #timeString + 1, th)
term.write(timeString)
os.sleep(0.1)
end
end,
function()
local pretty = require("cc.pretty")
local tw, th = term.getSize()
2023-10-19 20:27:14 +03:00
while true do
local _evd = { os.pullEvent() }
local ev, evd = table.remove(_evd, 1), _evd
if ev == "key" then
mplayer.heldKeys[evd[1]] = evd[2]
elseif ev == "key_up" then
mplayer.heldKeys[evd[1]] = nil
end
2023-10-19 20:27:14 +03:00
if ev == "key_up" and evd[1] == keys.q then
break
elseif ev == "key" and (evd[1] == keys.one or evd[1] == keys.f1) then
mplayer.currentScreen = 1
elseif ev == "key" and (evd[1] == keys.two or evd[1] == keys.f2) then
mplayer.currentScreen = 2
elseif ev == "key" and (evd[1] == keys.three or evd[1] == keys.f3) then
mplayer.currentScreen = 3
2023-10-19 20:27:14 +03:00
elseif ev == "key" and evd[1] == keys.f then
2023-10-20 02:16:46 +03:00
drive.seek(3000)
2023-10-19 20:27:14 +03:00
elseif ev == "key" and evd[1] == keys.b then
2023-10-20 02:16:46 +03:00
drive.seek(-3000)
elseif ev == "key" and evd[1] == keys.tab then
local dir = ((mplayer.heldKeys[keys.leftShift] ~= nil) or (mplayer.heldKeys[keys.rightShift] ~= nil)) and -1 or 1
mplayer.currentScreen = ((mplayer.currentScreen - 1 + #mplayer.screens + dir)) % #mplayer.screens + 1
elseif ev == "key" then
mplayer.screens[mplayer.currentScreen].handleKey(mplayer, evd[1], evd[2])
2023-10-19 20:27:14 +03:00
elseif ev == "mouse_scroll" then
local dir, x, y = table.unpack(evd)
mplayer.screens[mplayer.currentScreen].handleScroll(mplayer, dir, x, y)
2023-10-19 20:27:14 +03:00
elseif ev == "song_change" then
mplayer.statusLineScroll = 0
elseif (ev == "mouse_click" or ev == "mouse_drag") and evd[3] == th - 1 then
local p = (evd[2] - 1) / tw
local song = mplayer.songs[mplayer.currentSong]
2023-10-20 02:16:46 +03:00
drive.seek(-drive.getSize())
if song ~= nil then
2023-10-20 02:16:46 +03:00
drive.seek(song.offset + math.floor(song.length * p))
else
2023-10-20 02:16:46 +03:00
drive.seek(math.floor(p * drive.getSize()))
end
elseif (ev == "mouse_click" or ev == "mouse_drag") and evd[3] == 1 then
local cx, x = 1, evd[2]
for i, screen in ipairs(mplayer.screens) do
local caption = " "..i..""..screen.title.." "
if x >= cx and x <= (cx + #caption) then
mplayer.currentScreen = i
break
end
cx = cx + #caption
end
elseif ev == "term_resize" then
tw, th = term.getSize()
elseif ev == "tape_removed" then
mplayer.songs = {}
elseif ev == "tape_inserted" then
drive.stop()
drive.seek(-drive.getSize())
for i = 1, 48 do
local offset = read32()
local length = read32()
local title = drive.read(117)
title = title:sub(1, title:find("\x00"))
if length > 0 and offset > 0 then
mplayer.songs[i] = {
title = title,
offset = offset,
length = length
}
end
end
2023-10-19 20:27:14 +03:00
elseif ev ~= "timer" then
if drive.isDummy then
local m = term.redirect(peripheral.wrap("right"))
io.write(ev .. " ")
pretty.print(pretty.pretty(evd))
term.redirect(m)
end
2023-10-19 20:27:14 +03:00
end
end
end,
function()
while true do
mplayer.statusLineScroll = mplayer.statusLineScroll + 1
mplayer.screens[2].textScroll = mplayer.screens[2].textScroll + 1
os.sleep(0.25)
2023-10-19 20:27:14 +03:00
end
end,
function()
local oldSong = nil
local oldDriveState = nil
local oldTapeState = nil
2023-10-19 20:27:14 +03:00
while true do
mplayer.currentSong = 0
if drive._tick then drive._tick() end -- dummy mode
local tapeState = drive.isReady()
if tapeState ~= oldTapeState then
os.queueEvent(tapeState and "tape_inserted" or "tape_removed")
oldTapeState = tapeState
end
local driveState = drive.getState()
if driveState ~= oldDriveState then
os.queueEvent("drive_state", driveState)
oldDriveState = driveState
end
2023-10-20 02:16:46 +03:00
local pos = drive.getPosition()
2023-10-19 20:27:14 +03:00
for i, song in ipairs(mplayer.songs) do
2023-10-20 02:16:46 +03:00
if pos >= song.offset and pos < (song.offset + song.length) then
2023-10-19 20:27:14 +03:00
mplayer.currentSong = i
end
end
2023-10-19 20:27:14 +03:00
if oldSong ~= mplayer.currentSong then
os.queueEvent("song_change")
oldSong = mplayer.currentSong
end
2023-10-19 20:27:14 +03:00
os.sleep(0.1)
end
end
)