189 lines
5.1 KiB
Bash
Executable file
189 lines
5.1 KiB
Bash
Executable file
#!/bin/sh
|
|
# Kimapr's streaming setup
|
|
# how to use:
|
|
# install ncat, lua (tested with 5.4.3), and script
|
|
# mkdir ~/stream
|
|
# make a text file ~/stream/welcome, it will be displayed on stream startup.
|
|
# make a text file ~/stream/the_end, it will be displayed on stream end.
|
|
# start the stream by running this script (see usage in the echo command below)
|
|
# after it starts you can connect via the port provided from any interface
|
|
# end the stream by exitting from the shell in the stream window
|
|
# you can also replay past streams using `scriptreplay -O live -T live-timing` in ~/stream/hist/*/
|
|
|
|
echo "usage: tstream <port> <width> <height> [max bandwidth in KiB/s (per-client)]"
|
|
port=$1
|
|
width=$2
|
|
height=$3
|
|
bandwidth=$4
|
|
if [ "x$bandwidth" = "x" ]; then
|
|
bandwidth=32
|
|
fi
|
|
randid=`head -c 16 /dev/urandom | xxd -p`
|
|
name=`date -u +%Y-%m-%d_%H-%M-%S_UTC`
|
|
tmux new-session -d -s wstream_$randid "clear;cat ~/stream/welcome;$SHELL"
|
|
tmux resize-window -t wstream_$randid -x $width -y $(($height - 1))
|
|
tmux set-option -t wstream_$randid status-right "? viewers"
|
|
cat >/tmp/tstream-helper_$randid <<EOF
|
|
#!/bin/sh
|
|
clear
|
|
TMUX= tmux attach -t wstream_$randid
|
|
clear
|
|
cat ~/stream/the_end
|
|
for i in \$(seq 7); do
|
|
echo -n .
|
|
sleep 0.1
|
|
done
|
|
echo DISCONNECT
|
|
EOF
|
|
chmod +x /tmp/tstream-helper_$randid
|
|
mkdir -p ~/stream/hist/$name
|
|
tmux new-session -d -s stream_$randid "SHELL='/tmp/tstream-helper_$randid' script -f ~/stream/hist/$name/live -T ~/stream/hist/$name/live-timing;sleep 2"
|
|
tmux resize-window -t stream_$randid -x $width -y $height
|
|
cat >/tmp/tstream-refresh_$randid <<EOF
|
|
#!/usr/bin/env lua
|
|
local file=io.popen("tmux list-clients")
|
|
local lines={}
|
|
local line=file:read()
|
|
while line do
|
|
lines[#lines+1]=line
|
|
line=file:read()
|
|
end
|
|
local clients={}
|
|
for k,v in ipairs(lines) do
|
|
local cl,sess=string.match(v,"(.-)%: (.-) ")
|
|
if sess=="wstream_$randid" then
|
|
os.execute("tmux refresh-client -t "..cl)
|
|
end
|
|
end
|
|
EOF
|
|
echo 0 > /tmp/tstream-count_$randid
|
|
vcrefresh="tmux set-option -t wstream_$randid status-right \"\$(cat /tmp/tstream-count_$randid) viewers\""
|
|
sh -c "$vcrefresh"
|
|
cat >/tmp/tstream-smarttail_$randid <<EOF
|
|
#!/usr/bin/env lua
|
|
local unpack=unpack or table.unpack
|
|
local file=io.open("$HOME/stream/hist/$name/live")
|
|
file:seek("end")
|
|
local bandwidth=$bandwidth * 1024
|
|
local checkpoints={}
|
|
local coro=coroutine.create(function()
|
|
local file=io.open("/tmp/tstream-seektimes_$randid")
|
|
while true do
|
|
local curseek=file:seek()
|
|
local endseek=file:seek("end")
|
|
local avail=endseek-curseek
|
|
file:seek("set",curseek)
|
|
if avail>0 then
|
|
local str=file:read()
|
|
local seek,t=str:match("(.-) (.+)")
|
|
seek,t=tonumber(seek),tonumber(t)
|
|
if seek and t then
|
|
table.insert(checkpoints,{seek,t})
|
|
end
|
|
else
|
|
coroutine.yield()
|
|
end
|
|
end
|
|
end)
|
|
local ct=os.time()
|
|
local count=0
|
|
local counts={}
|
|
while true do
|
|
local curseek=file:seek()
|
|
local endseek=file:seek("end")
|
|
local avail=endseek-curseek
|
|
file:seek("set",curseek)
|
|
assert(coroutine.resume(coro))
|
|
if avail>0 then
|
|
local str=file:read(math.min(avail,512))
|
|
assert(str)
|
|
io.write(str)
|
|
io.flush()
|
|
count=count+#str
|
|
local cpc=#checkpoints
|
|
local avg=0
|
|
for k,v in pairs(counts) do
|
|
avg=avg+v
|
|
end
|
|
avg=avg/#counts
|
|
if avg>bandwidth then
|
|
os.execute("clear")
|
|
print("overload! "..(avg/1024).." KiB/s > "..(bandwidth/1024).." KiB/s")
|
|
while true do
|
|
os.execute("sleep 0.1")
|
|
assert(coroutine.resume(coro))
|
|
if #checkpoints>cpc then
|
|
cpc=#checkpoints
|
|
break
|
|
end
|
|
end
|
|
local seek=checkpoints[cpc][1]
|
|
print("seeking to "..seek.."/"..file:seek("end"))
|
|
os.execute("sleep 1")
|
|
counts={}
|
|
count=0
|
|
file:seek("set",checkpoints[cpc][1]) --congestion
|
|
end
|
|
else
|
|
os.execute("sleep 0.01")
|
|
end
|
|
local tf=io.open("/tmp/tstream-death_$randid")
|
|
if tf then
|
|
tf:close()
|
|
io.stdin:close()
|
|
io.stdout:close()
|
|
return
|
|
end
|
|
local ct2=os.time()
|
|
if ct2~=ct then
|
|
ct=ct2
|
|
table.insert(counts,count)
|
|
count=0
|
|
while #counts>5 do
|
|
table.remove(counts,1)
|
|
end
|
|
end
|
|
end
|
|
EOF
|
|
chmod +x /tmp/tstream-smarttail_$randid
|
|
cat >/tmp/tstream-cat_$randid <<EOF
|
|
#!/bin/sh
|
|
vcrefresh='$vcrefresh'
|
|
echo "\$vcrefresh"
|
|
{ sleep 5;/tmp/tstream-refresh_$randid; } &
|
|
echo "Welcome to Kimapr's stream. Please wait..."
|
|
echo \$((\$(cat /tmp/tstream-count_$randid) + 1)) > /tmp/tstream-count_$randid
|
|
sh -c "\$vcrefresh"
|
|
/tmp/tstream-smarttail_$randid
|
|
echo \$((\$(cat /tmp/tstream-count_$randid) - 1)) > /tmp/tstream-count_$randid
|
|
sh -c "\$vcrefresh"
|
|
EOF
|
|
chmod +x /tmp/tstream-cat_$randid
|
|
chmod +x /tmp/tstream-refresh_$randid
|
|
touch /tmp/tstream-seektimes_$randid
|
|
{
|
|
while true; do
|
|
sleep 5
|
|
echo "$(lua -e "local file=io.open(\"$HOME/stream/hist/$name/live\")print(file:seek(\"end\")..\" \"..os.time())file:close()")" >>/tmp/tstream-seektimes_$randid
|
|
/tmp/tstream-refresh_$randid
|
|
done
|
|
} &
|
|
ncat -l -k -c "/tmp/tstream-cat_$randid" $port &
|
|
sleep 1
|
|
tmux attach -t stream_$randid
|
|
tmux kill-session -t wstream_$randid
|
|
tmux kill-session -t stream_$randid
|
|
touch /tmp/tstream-death_$randid
|
|
echo PLEASE WAIT...
|
|
sleep 2;
|
|
rm /tmp/tstream-death_$randid
|
|
rm /tmp/tstream-helper_$randid
|
|
rm /tmp/tstream-refresh_$randid
|
|
rm /tmp/tstream-cat_$randid
|
|
rm /tmp/tstream-count_$randid
|
|
rm /tmp/tstream-smarttail_$randid
|
|
rm /tmp/tstream-seektimes_$randid
|
|
kill %1
|
|
kill %2
|
|
echo exit complete
|