WP integration with BBB to start/stop and download a video call recording
<?php | |
/* | |
Plugin Name: BBB Register | |
Plugin URI: | |
Description: Add support to start/stop and download videos from the BBB instance of Merge-IT. | |
Author: Daniele Mte90 Scasciafratte | |
Version: 1.0.0 | |
Author URI: | |
*/ | |
add_filter('manage_bbb-room_posts_columns', 'bbb_register_column'); | |
function bbb_register_column($columns){ | |
$columns[ 'record' ] = __( 'Stato Registrazione' ); | |
return $columns; | |
} | |
add_action( 'manage_bbb-room_posts_custom_column' , 'bbb_register_record_column', 10, 2 ); | |
function bbb_register_record_column( $column, $post_id ) { | |
if ( $column === 'record' ) { | |
if ( empty( get_option( 'bbb-recorder-status-' . get_the_ID() ) ) ) { | |
$nonce = wp_create_nonce( 'bbb_register_start' ); | |
echo '<a href="edit.php?post_type=bbb-room&bbb-register=true&bbb-room=' . get_the_ID() . '&&bbb-nonce=' . esc_attr( $nonce ) . '">Avvia</a>'; | |
} else { | |
$nonce = wp_create_nonce( 'bbb_register_stop' ); | |
echo '<a href="edit.php?post_type=bbb-room&bbb-stop=true&bbb-room=' . get_the_ID() . '&&bbb-nonce=' . esc_attr( $nonce ) . '">Ferma</a>'; | |
} | |
} | |
} | |
add_action( 'admin_init', 'bbb_register_endpoint' ); | |
function bbb_register_endpoint() { | |
if ( !\current_user_can( 'edit_bbb_rooms' ) ) { | |
return; | |
} | |
if ( empty( $_GET[ 'bbb-register' ] ) ) { | |
return; | |
} | |
if ( !wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_GET[ 'bbb-nonce' ] ) ), 'bbb_register_start' ) ) { | |
return; | |
} | |
$bbbroom = sanitize_text_field( \wp_unslash( $_GET[ 'bbb-room' ] ) ); | |
$bbbrom_slug = basename( get_permalink( $bbbroom ) ); | |
$bbb_id = get_post_meta( $bbbroom, 'bbb-room-meeting-id', true ); | |
update_option( 'bbb-recorder-status-' . $bbbroom, 'recording' ); | |
$request = wp_remote_get( 'http://eventi.merge-it.net:8081/?bbb_meeting=' . $bbbrom_slug . '&bbb_id=' . $bbb_id . '&bbb_add=true&bbb_secret=' . get_option( 'bigbluebutton_salt' ) ); | |
add_action( 'admin_notices', function() { | |
$class = 'notice notice-success'; | |
printf( '<div class="%1$s"><p>La registrazione sarà avviata in un minuto!</p></div>', esc_attr( $class ) ); | |
} ); | |
} | |
add_action( 'admin_init', 'bbb_stop_endpoint' ); | |
function bbb_stop_endpoint() { | |
if ( !\current_user_can( 'edit_bbb_rooms' ) ) { | |
return; | |
} | |
if ( empty( $_GET[ 'bbb-stop' ] ) ) { | |
return; | |
} | |
if ( !wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_GET[ 'bbb-nonce' ] ) ), 'bbb_register_stop' ) ) { | |
return; | |
} | |
$bbbroom = sanitize_text_field( \wp_unslash( $_GET[ 'bbb-room' ] ) ); | |
$bbbrom_slug = basename( get_permalink( $bbbroom ) ); | |
$bbb_id = get_post_meta( $bbbroom, 'bbb-room-meeting-id', true ); | |
$request = wp_remote_get( 'http://eventi.merge-it.net:8081/?bbb_meeting=' . $bbbrom_slug . '&bbb_id=' . $bbb_id . '&bbb_remove=true&bbb_secret=' . get_option( 'bigbluebutton_salt' ) ); | |
delete_option( 'bbb-recorder-status-' . $bbbroom, '' ); | |
add_action( 'admin_notices', function() { | |
$class = 'notice notice-success'; | |
printf( '<div class="%1$s"><p>La registrazione è stata fermata!</p></div>', esc_attr( $class ) ); | |
} ); | |
} | |
add_filter( 'the_content', 'bbb_add_download' ); | |
function bbb_add_download( $content ) { | |
if ( get_post_type() === 'bbb-room' ) { | |
$bbbrom_slug = basename( get_permalink( get_the_ID() ) ); | |
$content .= '<br>Download Link: <a href="http://eventi.merge-it.net:8081/?bbb_meeting=' . $bbbrom_slug . '&bbb_recording=true">Click here</a>'; | |
} | |
return $content; | |
} |
version: '3.3' | |
services: | |
bbb-streamer: | |
image: netvandal/livestreamingld:1.94 | |
container_name: your_meetingID | |
environment: | |
# BigBlueButton Server url: | |
- BBB_URL=URL | |
# BigBlueButton secret: | |
- BBB_SECRET=random | |
# BigBlueButton meetingID: | |
- BBB_MEETING_ID=your_meetingID | |
# start meeting (optional): | |
- BBB_START_MEETING=false | |
# meeting title (optional): | |
- BBB_MEETING_TITLE=liveStreaming | |
# download / save BigBlueButton meeting | |
- BBB_DOWNLOAD_MEETING=true | |
# play intro file (can be a local file in videodata folder e.g. /video/intro.mp4 or a url of a mediastream e.g. https://my.intro.stream) | |
- BBB_INTRO=false | |
# fake url to live without troubles | |
- BBB_STREAM_URL=rmtp://fakeurl.com/stream | |
# Timezone (default: Europe/Vienna): | |
- TZ=Europe/Rome | |
volumes: | |
- ./videodata:/video |
#!/usr/bin/env python3 | |
# pip3 install pyyaml | |
from http.server import BaseHTTPRequestHandler, HTTPServer | |
import json | |
import yaml | |
import urllib | |
import os | |
import shutil | |
import sys | |
class HTTPServer_RequestHandler(BaseHTTPRequestHandler): | |
def setup(self): | |
BaseHTTPRequestHandler.setup(self) | |
self.request.settimeout(180) | |
def do_GET(self): | |
parsed_path = urllib.parse.urlsplit(self.path) | |
query = urllib.parse.parse_qs(parsed_path.query) | |
self.send_response(200) | |
message = '' | |
bbb_meeting = '' | |
if 'bbb_meeting' not in query: | |
self.send_response(300) | |
message = {'status': 'error', 'text': 'you are looking to a private web server! Go away!'} | |
else: | |
bbb_meeting = ' '.join(map(str, query['bbb_meeting'])) | |
dockercomposefolder = os.getcwd() + '/bbb-record-' + bbb_meeting | |
dockercompose = dockercomposefolder + '/docker-compose.yml' | |
video = dockercomposefolder + '/videodata/' | |
if 'bbb_secret' in query: | |
os.system('cd /root') | |
if not os.path.exists(os.getcwd() + '/docker-bbb-base.yml'): | |
print(os.getcwd() + '/docker-bbb-base.yml not exists!') | |
sys.exit() | |
with open(os.getcwd() + '/docker-bbb-base.yml') as f: | |
data = yaml.safe_load(f) | |
message = '' | |
for item in data['services']['bbb-streamer']['environment']: | |
if item == 'BBB_SECRET=' + ' '.join(map(str, query['bbb_secret'])): | |
message = {'status': 'success', 'text': 'secret found'} | |
break | |
if message == '': | |
self.send_response(300) | |
message = {'status': 'error', 'text': 'wrong secret'} | |
if 'bbb_meeting' in query: | |
bbb_id = ' '.join(map(str, query['bbb_id'])) | |
if 'bbb_add' in query: | |
fin = open(os.getcwd() + '/docker-bbb-base.yml', "rt") | |
message = {'status': 'success', 'text': 'meeting configured'} | |
if os.path.exists(dockercomposefolder): | |
shutil.rmtree(dockercomposefolder, ignore_errors=True) | |
message = {'status': 'success', 'text': 'meeting already exist, removed and created again'} | |
os.mkdir(dockercomposefolder) | |
fout = open(dockercompose, "wt") | |
for line in fin: | |
fout.write(line.replace('your_meetingID', bbb_id).replace('containerID', bbb_meeting)) | |
fin.close() | |
fout.close() | |
os.system('cd ' + dockercomposefolder + ' && docker-compose up --force-recreate --build -d &') | |
message = {'status': 'success', 'text': 'docker container started'} | |
elif 'bbb_remove' in query: | |
if os.path.exists(dockercomposefolder): | |
os.system('cd ' + dockercomposefolder + ' && docker-compose down &') | |
#os.remove(dockercompose) | |
message = {'status': 'success', 'text': 'meeting recording stopped'} | |
if 'bbb_recording' in query: | |
if os.path.isdir(video): | |
for i in os.listdir(video): | |
if os.path.isfile(os.path.join(video, i)) and 'record' in i: | |
self.send_header("Content-Type", 'application/octet-stream') | |
with open(os.path.join(video, i), 'rb') as f: | |
self.send_header("Content-Disposition", 'attachment; filename="{}"'.format(i)) | |
fs = os.fstat(f.fileno()) | |
self.send_header("Content-Length", str(fs.st_size)) | |
self.end_headers() | |
try: | |
shutil.copyfileobj(f, self.wfile) | |
except: | |
print('Error on downloading ' + os.path.join(video, i)) | |
else: | |
self.send_response(300) | |
message = {'status': 'error', 'text': 'recording not found'} | |
else: | |
message = {'status': 'success', 'text': 'recording not found, did you started it?'} | |
if message != '': | |
self.send_header('Content-type', 'text/json') | |
try: | |
self.end_headers() | |
except BrokenPipeError: | |
print('Browser blocked the download') | |
self.wfile.write(bytes(json.dumps(message), "utf8")) | |
return | |
#def log_message(self, format, *args): | |
#return | |
def run(): | |
print('Server started...') | |
server_address = ('', 8081) | |
httpd = HTTPServer(server_address, HTTPServer_RequestHandler) | |
print('Server running...') | |
httpd.serve_forever() | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment