main
Daniel Havlik 2021-07-30 10:13:26 +02:00
commit 3a1bb6176a
41 changed files with 915 additions and 0 deletions

1
.pid Executable file
View File

@ -0,0 +1 @@
32348

BIN
.play_sound.sh.swp Executable file

Binary file not shown.

1
S1_ninjasecret Executable file
View File

@ -0,0 +1 @@
tcosZooZsOoEOaOcctNVNHVZ

1
S1_pause Executable file
View File

@ -0,0 +1 @@
disabled

1
S2_ninjasecret Executable file
View File

@ -0,0 +1 @@
soEataEtOaEosascoOOENsoV

1
S2_pause Executable file
View File

@ -0,0 +1 @@
enabled

1
S3_ninjasecret Executable file
View File

@ -0,0 +1 @@
aVcHoONsEcsVNaNtoZZEcHVV

1
S3_pause Executable file
View File

@ -0,0 +1 @@
enabled

1
bee Executable file
View File

@ -0,0 +1 @@
🐝

BIN
countdown_s1.mp4 Executable file

Binary file not shown.

BIN
countdown_s2.mp4 Executable file

Binary file not shown.

BIN
countdown_s3.mp4 Executable file

Binary file not shown.

1
curtime_S1.json Executable file
View File

@ -0,0 +1 @@
{"length": 18265.0, "elapsed": 3584.6}

5
get_time.py Executable file
View File

@ -0,0 +1,5 @@
import socket
byte_message = bytes("get_time\n", " utf-8")
opened_socket = socket.socket(socket. AF_INET, socket. SOCK_DGRAM)
opened_socket. sendto(byte_message, ("127.0.0.1", 7123))

17
move_window.sh Executable file
View File

@ -0,0 +1,17 @@
wid=`xdotool getactivewindow`
max_state=`xprop -id $wid _NET_WM_STATE`
wmctrl -ir $wid -b remove,maximized_vert,maximized_horz
eval `xdotool getwindowgeometry --shell $wid`
new_x=$1
if [[ "$X" -ge "$new_x" ]]; then
new_x=0
fi
xdotool windowmove $wid $new_x $Y
if [ -z "${max_state/*_NET_WM_STATE_MAXIMIZED_*/}" ]; then
wmctrl -ir $wid -b add,maximized_vert,maximized_horz
fi
xdotool windowraise $wid

40
obs_hotkey_helper.py Executable file
View File

@ -0,0 +1,40 @@
import os
import json
import socket
import subprocess
import obswebsocket, obswebsocket.requests
UDP_IP_ADDRESS = "127.0.0.1"
UDP_PORT_NO = 7127
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
client = obswebsocket.obsws("localhost", 4444, "password")
client.connect()
res = client.call(obswebsocket.requests.SetSourceFilterVisibility("FS_vorhang", "vorhang_li_auf", True))
print(res)
def ssfv(cmd):
params = cmd[len("SetSourceFilterVisibility")+1:]
print(params)
item, filt, vis = params.split('.')
if vis.lower() in ('0', 'false', 'f', 'n', 'no', 'nein', ''):
vis = False
else:
vis = True
res = client.call(obswebsocket.requests.SetSourceFilterVisibility(item, filt, vis))
while True:
data, addr = serverSock.recvfrom(1024)
commands = data.decode("utf8").splitlines()
for cmd in commands:
if cmd.startswith('SetSourceFilterVisibility'):
ssfv(cmd)
client.disconnect()

1
play.json Executable file
View File

@ -0,0 +1 @@
{"S1": "", "S2": "", "S3": ""}

10
play_sound.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
# play the file
cmd="exec /usr/bin/mpv $1 & echo $$! > $2.pid"
echo $cmd
sh -c "$cmd"
# if pid still exists, press button
if test -f "$2.pid"; then
./send_companion.py $3 $4
fi

107
play_udp.py Executable file
View File

@ -0,0 +1,107 @@
import os
import json
import socket
import subprocess
UDP_IP_ADDRESS = "127.0.0.1"
UDP_PORT_NO = 7123
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
SIDS = ('S1', 'S2', 'S3')
mplayers = dict(S1=None, S2=None, S3=None)
import io
PIPE = io.StringIO()
SOUNDS = dict(blubber='/home/kombinat/player/test.mp3', short='/home/kombinat/player/cough.mp3')
#for sid in SIDS:
# if os.path.isdir(f'/tmp/mplayerctrl{sid}'):
# os.unlink(f'/tmp/mplayerctrl{sid}')
# os.mkfifo(f'/tmp/mplayerctrl{sid}')
def _get_current():
res = []
with open('play.json') as playconf:
for screen_id, filepath in json.loads(playconf.read()).items():
if filepath == '':
continue
res.append((screen_id, filepath))
return res
def _mplayer_command(screen_id, mplayercmd):
with open(f'/tmp/mplayerctrl{screen_id}', 'a') as ctrl:
ctrl.write(mplayercmd)
def get_time():
for screen_id, filepath in _get_current():
_mplayer_command(screen_id, 'pausing_keep_force get_time_pos\n')
def load_current():
for screen_id, filepath in _get_current():
cmd = f'loadfile storage/{filepath}\npause\npausing_keep get_time_length\n'
_mplayer_command(screen_id, cmd)
_mplayer_command(screen_id, f'pausing_keep_force run "echo ${{pause}} > {screen_id}_pause"\n')
def play_sound(cmd):
cmd = cmd[6:]
if cmd.startswith('kill'):
snd = cmd[5:]
os.system(f'kill -9 `cat {snd}.pid`')
os.unlink(f'{snd}.pid')
return
cmd, addr = cmd.split('#')
bank, btn = addr.split('_')
os.system(f'./play_sound.sh {SOUNDS[cmd]} {cmd} {int(bank)} {int(btn)} &')
def play_current():
for screen_id, filepath in _get_current():
_mplayer_command(screen_id, f'pause\n')
_mplayer_command(screen_id, f'pausing_keep_force run "echo ${{pause}} > {screen_id}_pause"\n')
def stop_current():
for screen_id, filepath in _get_current():
with open(f'/tmp/mplayerctrl{screen_id}', 'a') as ctrl:
ctrl.write("stop\n")
os.unlink(f'curtime_{screen_id}.json')
def ninja(cmd):
for sid in SIDS:
if f'{sid}' in cmd:
scr = sid
break
scr = scr[1]
if cmd.endswith('start'):
os.system(f'./start_ninja.sh {scr}')
elif cmd.endswith('stop'):
os.system(f'./stop_ninja.sh {scr}')
while True:
data, addr = serverSock.recvfrom(1024)
commands = data.decode("utf8").splitlines()
for cmd in commands:
if cmd == 'load_current':
load_current()
elif cmd == 'play_current':
play_current()
elif cmd == 'stop_current':
stop_current()
elif cmd == 'get_time':
get_time()
elif cmd.startswith('sound'):
play_sound(cmd)
elif cmd.startswith('ninja'):
ninja(cmd)
else:
print(f"{cmd} not found!")

48
play_udp.py_backup Executable file
View File

@ -0,0 +1,48 @@
import os
## Again we import the necessary socket python module
import socket
## Here we define the UDP IP address as well as the port number that we have
## already defined in the client python script.
UDP_IP_ADDRESS = "127.0.0.1"
UDP_PORT_NO = 7000
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
## One difference is that we will have to bind our declared IP address
## and port number to our newly declared serverSock
serverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
# screen "names" to xinerama screen number
screen_map = dict(S1=1, S2=2, S3=3)
for sid, xscr in screen_map.items():
os.mkfifo(f'/tmp/mplayerctrl{sid}')
os.system(f'mplayer -xineramascreen {xscr} -fs -idle -really-quiet -slave -input file=/tmp/mplayerctrl{sid} &')
import json
while True:
data, addr = serverSock.recvfrom(1024)
commands = data.decode("utf8").splitlines()
for cmd in commands:
if cmd == 'play_current':
mplayercmd = []
with open('play.json') as playconf:
for screen_id, filepath in json.loads(playconf.read()).items():
if filepath == '':
continue
xscreen = screen_map[screen_id]
mplayercmd.append(f'mplayer -fs -slave -xineramascreen {xscreen} storage/{filepath}')
os.system(' & '.join(mplayercmd) + "&")
elif cmd == 'stop_current':
os.system('killall mplayer')
elif cmd.startswith('ninja'):
if 's1' in cmd:
scr = '1'
elif 's2' in cmd:
scr = '2'
elif 's3' in cmd:
scr = '3'
if cmd.endswith('start'):
os.system(f'./start_ninja.sh {scr}')
elif cmd.endswith('stop'):
os.system(f'./stop_ninja.sh {scr}')

52
play_udp.py_mplayerctl Executable file
View File

@ -0,0 +1,52 @@
import os
## Again we import the necessary socket python module
import socket
## Here we define the UDP IP address as well as the port number that we have
## already defined in the client python script.
UDP_IP_ADDRESS = "127.0.0.1"
UDP_PORT_NO = 7000
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
## One difference is that we will have to bind our declared IP address
## and port number to our newly declared serverSock
serverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
# screen "names" to xinerama screen number
screen_map = dict(S1=1, S2=2, S3=3)
for sid, xscr in screen_map.items():
os.unlink(f'/tmp/mplayerctrl{sid}')
os.mkfifo(f'/tmp/mplayerctrl{sid}')
print(f'mplayer -xineramascreen {xscr} -fs -idle -really-quiet -slave -input file=/tmp/mplayerctrl{sid} &')
#os.system(f'mplayer -xineramascreen {xscr} -fs -idle -really-quiet -slave -input file=/tmp/mplayerctrl{sid} &')
import json
while True:
data, addr = serverSock.recvfrom(1024)
commands = data.decode("utf8").splitlines()
for cmd in commands:
if cmd == 'play_current':
with open('play.json') as playconf:
for screen_id, filepath in json.loads(playconf.read()).items():
if filepath == '':
continue
xscreen = screen_map[screen_id]
mplayercmd = f'loadfile {filepath}\n'
with open(f'/tmp/mplayerctrl{screen_id}', 'a') as ctrl:
ctrl.write(mplayercmd)
elif cmd == 'stop_current':
for sid in ('S1', 'S2', 'S3'):
with open(f'/tmp/mplayerctrl{sid}', 'a') as ctrl:
ctrl.write("stop\n")
elif cmd.startswith('ninja'):
if 's1' in cmd:
scr = '1'
elif 's2' in cmd:
scr = '2'
elif 's3' in cmd:
scr = '3'
if cmd.endswith('start'):
os.system(f'./start_ninja.sh {scr}')
elif cmd.endswith('stop'):
os.system(f'./stop_ninja.sh {scr}')

92
play_udp.pyzw Executable file
View File

@ -0,0 +1,92 @@
import os
import json
import socket
import subprocess
UDP_IP_ADDRESS = "127.0.0.1"
UDP_PORT_NO = 7000
serverSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSock.bind((UDP_IP_ADDRESS, UDP_PORT_NO))
SIDS = ('S1', 'S2', 'S3')
mplayers = dict(S1=None, S2=None, S3=None)
import io
PIPE = io.StringIO()
for sid in SIDS:
os.unlink(f'/tmp/mplayerctrl{sid}')
os.mkfifo(f'/tmp/mplayerctrl{sid}')
def _get_current():
res = []
with open('play.json') as playconf:
for screen_id, filepath in json.loads(playconf.read()).items():
if filepath == '':
continue
res.append((screen_id, filepath))
return res
def _mplayer_command(screen_id, mplayercmd):
with open(f'/tmp/mplayerctrl{screen_id}', 'a') as ctrl:
ctrl.write(mplayercmd)
def get_time():
for screen_id, filepath in _get_current():
_mplayer_command(screen_id, 'pausing_keep_force get_time_pos\n')
def load_current():
#XXX report back loading to webinterface
for screen_id, filepath in _get_current():
cmd = f'loadfile storage/{filepath}\npause\npausing_keep get_time_length\n'
_mplayer_command(screen_id, cmd)
_mplayer_command(screen_id, f'pausing_keep_force run "echo ${{pause}} > {screen_id}_pause"\n')
def play_current():
for screen_id, filepath in _get_current():
_mplayer_command(screen_id, f'pause\n')
_mplayer_command(screen_id, f'pausing_keep_force run "echo ${{pause}} > {screen_id}_pause"\n')
def stop_current():
for screen_id, filepath in _get_current():
with open(f'/tmp/mplayerctrl{screen_id}', 'a') as ctrl:
ctrl.write("stop\n")
os.unlink(f'curtime_{screen_id}.json')
def ninja(cmd):
for sid in SIDS:
if f'{sid}' in cmd:
scr = sid
break
scr = scr[1]
if cmd.endswith('start'):
os.system(f'./start_ninja.sh {scr}')
elif cmd.endswith('stop'):
os.system(f'./stop_ninja.sh {scr}')
while True:
data, addr = serverSock.recvfrom(1024)
commands = data.decode("utf8").splitlines()
for cmd in commands:
print(cmd)
if cmd == 'load_current':
load_current()
elif cmd == 'play_current':
play_current()
elif cmd == 'stop_current':
stop_current()
elif cmd == 'get_time':
get_time()
elif cmd.startswith('ninja'):
ninja(cmd)
else:
print(f"{cmd} not found!")

146
play_web.py Executable file
View File

@ -0,0 +1,146 @@
import time
import os
from flask import Flask, render_template, request, make_response, redirect
import json
import random
import socket
app = Flask("chaoszone-tv-media")
APPROOT = '/'
class ReverseProxied(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
script_name = environ.get('HTTP_X_SCRIPT_NAME', '')
if script_name:
environ['SCRIPT_NAME'] = script_name
path_info = environ['PATH_INFO']
if path_info.startswith(script_name):
environ['PATH_INFO'] = path_info[len(script_name):]
scheme = environ.get('HTTP_X_SCHEME', '')
if scheme:
environ['wsgi.url_scheme'] = scheme
return self.app(environ, start_response)
app.wsgi_app = ReverseProxied(app.wsgi_app)
def to_dict(args):
outdict = {}
for key, val in args.items():
outdict[key] = val
return outdict
def list_files():
filelist = os.listdir('storage/')
return sorted(filelist)
def get_ninja_secrets():
secrets = dict()
for scr in ['S1', 'S2', 'S3']:
with open(f'{scr}_ninjasecret') as infile:
secret = infile.read()
secrets[scr] = secret
return secrets
def regenerate_secret(scr):
new_secret = ''
for i in range(24):
new_secret += random.choice('cHaOsZoNEtV')
with open(f'{scr}_ninjasecret', 'w') as secfile:
secfile.write(new_secret)
def request_time():
byte_message = bytes("get_time", "utf-8")
with socket.socket(socket. AF_INET, socket. SOCK_DGRAM) as opened_socket:
opened_socket.sendto(byte_message, ("127.0.0.1", 7123))
time.sleep(0.1)
@app.route('/get_time.json')
def get_time():
request_time()
res = {}
for sid in ('S1', 'S2', 'S3'):
if not os.path.isfile(f'curtime_{sid}.json'):
continue
with open(f'curtime_{sid}.json') as curtime:
res[sid] = json.loads(curtime.read())
if not os.path.isfile(f'{sid}_pause'):
continue
with open(f'{sid}_pause') as pause:
res[sid]['pause'] = pause.read().strip()
r = make_response(json.dumps(res))
r.mimetype = 'application/json'
return r
@app.route('/media.html')
def media():
edit = False
data = to_dict(request.args)
if 'edit' in data:
edit = True
filelist = list_files()
secrets = get_ninja_secrets()
return render_template(
'media.html',
filelist=filelist,
secrets=secrets,
screens=['S1', 'S2','S3'],
edit=edit,
approot=APPROOT)
@app.route('/obs_multiview.html')
def obs_multiview():
return render_template(
'obs_multiview.html',
approot=APPROOT)
@app.route('/programm.html')
def atem_multiview():
return render_template(
'programm.html',
approot=APPROOT)
@app.route('/get_media')
def get_media():
with open('play.json') as playfile:
jsn = playfile.read()
r = make_response(jsn)
r.mimetype = 'application/json'
return r
@app.route('/set_media')
def set_media():
filelist = list_files()
to_set = to_dict(request.args)
for s in ('S1', 'S2', 'S3'):
if to_set[s] not in filelist:
to_set[s] = ''
with open('play.json', 'w') as playfile:
playfile.write(json.dumps(to_set))
return redirect('/media.html')
@app.route('/regenerate_ninja_link')
def regenerate_ninja_link():
scr = to_dict(request.args).get('scr')
regenerate_secret(scr)
return redirect('/media.html')

1
pos Executable file
View File

@ -0,0 +1 @@
99

42
run_mplayers.py Executable file
View File

@ -0,0 +1,42 @@
import subprocess
import sys
import json
screen_mapping = dict(S1='1', S2='2', S3='3')
scr = sys.argv[1]
info = dict()
def dump_info(info):
with open(f'curtime_{scr}.json', 'w') as curtime:
curtime.write(json.dumps(info))
def execute(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Poll process for new output until finished
for line in iter(process.stdout.readline, ""):
line = line.decode('utf8')
print(line)
if line.startswith('ANS_TIME_POSITION'):
info['elapsed'] = float(line[18:].strip())
dump_info(info)
elif line.startswith('ANS_LENGTH'):
info['length'] = float(line[11:].strip())
dump_info(info)
process.wait()
exitCode = process.returncode
if (exitCode == 0):
return 1
else:
raise Exception(command, exitCode, output)
execute([f'mplayer -xineramascreen {screen_mapping[scr]} -fs -idle -quiet -slave -input file=/tmp/mplayerctrl{scr}'])

1
s3_pid Executable file
View File

@ -0,0 +1 @@
901685

12
send_companion.py Executable file
View File

@ -0,0 +1,12 @@
#!/home/kombinat/player/bin/python
import sys
from pythonosc import udp_client
UDP_IP = "127.0.0.1"
UDP_PORT = 12321
client = udp_client.SimpleUDPClient(UDP_IP, UDP_PORT)
client.send_message(f'/press/bank/{int(sys.argv[1])}/{int(sys.argv[2])}', None)

9
start_ninja.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
#let "rnd = $RANDOM"
#cp -r ffprofile profiles/$rnd
let "w = 1680 * ($1 - 1)"
echo $w
#firefox --profile profiles/$rnd --new-instance --kiosk https://ninja.c3voc.de/?view=`cat S$1_ninjasecret`\&s\&vb=5000\&buffer & sleep 2 && ./move_window.sh $w
chromium --user-data-dir=/home/kombinat/crtmp$1 --autoplay-policy=no-user-gesture-required --new-window "%1" --window-position=$w,1080 --kiosk https://ninja.c3voc.de/?view=`cat S$1_ninjasecret`\&s\&vb=5000\&buffer &
echo $! > s$1_pid
#echo $rnd > s$1_profile

2
start_webserver.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
FLASK_APP=play_web.py bin/flask run -h 127.0.0.1

7
static/clipboard.min.js vendored Executable file

File diff suppressed because one or more lines are too long

2
static/jquery-3.5.1.min.js vendored Executable file

File diff suppressed because one or more lines are too long

29
static/main.css Executable file
View File

@ -0,0 +1,29 @@
body {
background-color: #abc;
}
body.multiview {
margin: 0;
}
body.multiview iframe {
position:absolute;
top: 0;
left:0;
right:0;
bottom:0;
}
#beendicator {
display: none;
}
tr.t-5 td {
background-color: orange;
}
tr.t-1 td {
background-color: red;
color: white;
}

107
static/main.js Executable file
View File

@ -0,0 +1,107 @@
var get_media = function() {
$.get('get_media', function(res) {
$('#S1 .filename').text(res.S1);
$('#S2 .filename').text(res.S2);
$('#S3 .filename').text(res.S3);
});
window.setTimeout(get_media, 2000);
}
window.setTimeout(get_media, 2000);
var curstate = {};
curstate.S1 = {};
curstate.S1.elapsed = null;
curstate.S1.len = null;
curstate.S1.elapsed_start = null;
curstate.S1.pause = '';
curstate.S2 = {};
curstate.S2.elapsed = null;
curstate.S2.len = null;
curstate.S2.elapsed_start = null;
curstate.S2.pause = '';
curstate.S3 = {};
curstate.S3.elapsed = null;
curstate.S3.len = null;
curstate.S3.elapsed_start = null;
curstate.S3.pause = '';
var update_elapsed_one = function(mystate, my_id) {
if (mystate.pause !== 'enabled' && mystate.elapsed !== null) {
var to_add = (Date.now() - mystate.elapsed_start) / 1000;
$(my_id + ' .remaining').text(formattimestamp(mystate.len - (mystate.elapsed + to_add)));
}
}
var update_elapsed = function() {
update_elapsed_one(curstate.S1, '#S1');
update_elapsed_one(curstate.S2, '#S2');
update_elapsed_one(curstate.S3, '#S3');
window.setTimeout(update_elapsed, 100);
}
window.setTimeout(update_elapsed, 100);
var formattimestamp = function(tme) {
return (tme/60>>0) + ':' + (tme % 60).toFixed(1);
}
var sync_stuff = function(my_res, mystate, my_id) {
if (my_res !== undefined) {
$(my_id + ' .length').text(formattimestamp(my_res.length));
$(my_id + ' .remaining').text(formattimestamp(my_res.length - my_res.elapsed));
mystate.len = my_res.length;
mystate.elapsed = my_res.elapsed;
mystate.pause = my_res.pause;
remaining = mystate.len - mystate.elapsed;
if (remaining < 60) {
$(my_id + '').removeClass('t-5');
$(my_id + '').addClass('t-1');
} else if (remaining < (60 * 5)) {
// 5 minutes left
$(my_id + '').addClass('t-5');
$(my_id + '').removeClass('t-1');
} else {
$(my_id + '').removeClass('t-5');
$(my_id + '').removeClass('t-1');
}
console.log('Setting elapsed to ' + mystate.elapsed);
mystate.elapsed_start = Date.now();
} else {
$(my_id + ' .length').text("");
$(my_id + ' .remaining').text("");
$(my_id + '').removeClass('t-5');
$(my_id + '').removeClass('t-1');
mystate.elapsed = null;
mystate.elapsed_start = null;
mystate.pause = '';
}
}
var get_time = function() {
$.get('get_time.json', function(res) {
sync_stuff(res.S1, curstate.S1, '#S1');
sync_stuff(res.S2, curstate.S2, '#S2');
sync_stuff(res.S3, curstate.S3, '#S3');
});
window.setTimeout(get_time, 600);
}
window.setTimeout(get_time, 600);
function copyToClipboard(element, scr) {
var $temp = $("<input>");
$("body").append($temp);
$temp.val($(element).text()).select();
document.execCommand("copy");
$temp.remove();
$("#linkfor").text(scr);
$("#beendicator").fadeIn();
window.setTimeout(function() { $("#beendicator").fadeOut(); }, 3000);
}

7
stop_ninja.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
kill -9 `cat s$1_pid`
rm s$1_pid
cd profiles
rm -rf `cat ../s$1_profile`
cd ..
rm s$1_profile

BIN
templates/.media.html.swp Executable file

Binary file not shown.

100
templates/media.html Executable file
View File

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='main.css') }}">
<title>chaoszone.tv media control</title>
</head>
<body>
{% if not edit %}
<h3>PLAY CUR:</h3>
<table border="1">
<tr>
<th>SCR</th>
<th>Filename</th>
<th>Length</th>
<th>Remaining</th>
</tr>
{% for scr in screens %}
<tr id="{{ scr }}">
<td><strong>{{ scr }}</strong></td>
<td class="filename">Loading …</td>
<td class="length"></td>
<td class="remaining"></td>
</tr>
{% endfor %}
</table>
<a href="media.html?edit">[ Edit ]</a>
{% endif %}
{% if edit %}
<h4>Edit PLAY CUR:</h4>
<form action="/set_media">
<label for="s1_sel"><strong>S1:</strong></label>
<select name="S1" id="s1_sel" type="list">
<option value="">blank</option>
{% for filename in filelist %}
<option value="{{ filename }}">{{ filename }}</option>
{% endfor %}
</select><br/>
<label for="s2_sel"><strong>S2:</strong> </label>
<select name="S2" id="s2_sel" type="list">
<option value="">blank</option>
{% for filename in filelist %}
<option value="{{ filename }}">{{ filename }}</option>
{% endfor %}
</select><br/>
<label for="s3_sel"><strong>S3:</strong> </label>
<select name="S3" id="s3_sel" type="list">
<option value="">blank</option>
{% for filename in filelist %}
<option value="{{ filename }}">{{ filename }}</option>
{% endfor %}
</select><br/>
<input type="submit" value="Save" />
</form>
{% endif %}
<h3>Ninja Links for Camera/Screenshare</h3>
<span id="beendicator">🐝 <strong>Good. Link for <span id="linkfor"></span> copied.</strong> 🐝<br/></span>
<strong>S1 (Slides):</strong>
<button onclick="copyToClipboard('#s1_sec', 'S1')">Copy</button> <a href="/regenerate_ninja_link?scr=S1">[regenerate]</a>
<span id="s1_sec" >https://ninja.c3voc.de/?push={{ secrets['S1'] }}</span> <br/>
<strong>S2 (Speaker):</strong>
<button onclick="copyToClipboard('#s2_sec', 'S2')">Copy</button> <a href="/regenerate_ninja_link?scr=S2">[regenerate]</a>
<span id="s2_sec" >https://ninja.c3voc.de/?push={{ secrets['S2'] }}</span> <br/>
<strong>S3 (Herald):</strong>
<button onclick="copyToClipboard('#s3_sec', 'S3')">Copy</button> <a href="/regenerate_ninja_link?scr=S3">[regenerate]</a>
<span id="s3_sec" >https://ninja.c3voc.de/?push={{ secrets['S3'] }}</span> <br/>
<h3>Build your own setup with these links:</h3>
<a href="https://studio.chaoszone.tv/obs_multiview.html" target="_blank">
OBS Multiview
</a><br />
<a href="https://studio.chaoszone.tv/programm.html" target="_blank">
Programm
</a><br />
<a href="https://studio.chaoszone.tv/emulator.html" target="_blank">
Streamdeck Emulator
</a><br />
<a href="https://studio.chaoszone.tv/media.html" target="_blank">
Media control
</a><br />
<script src="{{ url_for('static',filename='clipboard.min.js') }}"></script>
<script src="{{ url_for('static',filename='jquery-3.5.1.min.js') }}"></script>
<script src="{{ url_for('static',filename='main.js') }}"></script>
</body>
</html>

14
templates/obs_multiview.html Executable file
View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>chaoszone.tv obs multiview</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='main.css') }}">
</head>
<body class="multiview" style="margin:0">
<iframe src="https://ninja.c3voc.de/?view=kj4hieuz7893hv" style="border: 0; width: 100%; height: 100%" width="100%" height="100%"></iframe>
</body>
</html>

14
templates/programm.html Executable file
View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>chaoszone.tv obs multiview</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='main.css') }}">
</head>
<body class="multiview" style="margin:0">
<iframe src="https://ninja.c3voc.de?view=sdjjerkhhhr&vbr=500" style="border: 0; width: 100%; height: 100%" width="100%" height="100%"></iframe>
</body>
</html>

2
ticker_lg.txt Executable file
View File

@ -0,0 +1,2 @@
+++ EIL +++ EIL +++ EIL +++ EIL

8
www/interface.html Executable file
View File

@ -0,0 +1,8 @@
<html>
<body>
<iframe style="float:left;" src="/obs_multiview.html" width="49%" height="50%"></iframe>
<iframe style="float: left" src="/programm.html" width="49%" height="50%"></iframe>
<iframe style="float: left; display: block; width:1000px; height: 50%; overflow:hidden;" scrolling="no" seamless="seamless" src="/emulator.html" width="1000px" height="50%"></iframe>
<iframe style="float:left; display: block; width:700px; height: 50%; overflow:hidden;" scrolling="no" seamless="seamless" src="/media.html" height="50%"></iframe>
</body>
</html>

31
www/media.html Executable file
View File

@ -0,0 +1,31 @@
<html>
<body>
<form action="/save_media">
<label for="s1_sel">S1</label>
<select name="s1" id="s1_sel" type="list">
<option value="">blank</option>
<option value="video1.mkv">video1.mkv</option>
<option value="video2.mkv">video2.mkv</option>
<option value="video3.mkv">video3.mkv</option>
<option value="image.jpg">image.jpg</option>
</select>
<label for="s2_sel">S2</label>
<select name="s2" id="s2_sel" type="list">
<option value="">blank</option>
<option value="video1.mkv">video1.mkv</option>
<option value="video2.mkv">video2.mkv</option>
<option value="video3.mkv">video3.mkv</option>
<option value="image.jpg">image.jpg</option>
</select>
<label for="s3_sel">S3</label>
<select name="s3" id="s3_sel" type="list">
<option value="">blank</option>
<option value="video1.mkv">video1.mkv</option>
<option value="video2.mkv">video2.mkv</option>
<option value="video3.mkv">video3.mkv</option>
<option value="image.jpg">image.jpg</option>
</select>
<input type="submit" value="Save" />
</form>
</body>
</html>