115 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| #!/usr/bin/php
 | |
| <?php
 | |
| 
 | |
| /* -------------------------------------------------------------- */
 | |
| 
 | |
| // Options
 | |
| $opts = getopt('c:');
 | |
| 
 | |
| // Basic functions
 | |
| function logger($tabs = 1, $txt, $lvl = 1, $exit = false)
 | |
| {
 | |
|     global $_set;
 | |
| 
 | |
|     if ($lvl >= $_set->loglevel)
 | |
|         echo "[".date('Y-m-d H:i:s')."]".str_repeat("\t", $tabs)."$txt\n";
 | |
|     if ($exit)
 | |
|         exit;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| function is_dir_empty($dir)
 | |
| {
 | |
|     if (!is_readable($dir)) return NULL;
 | |
|     return (count(scandir($dir)) == 2);
 | |
| }
 | |
| 
 | |
| function notify($sub, $msg, $loglevel = 1)
 | |
| {
 | |
| 	global $_set;
 | |
| 
 | |
| 	if (is_array($_set->mail) && !empty($_set->mail))
 | |
| 		foreach ($_set->mail AS $mail)
 | |
| 			if (!@mail($mail, "=?UTF-8?B?".base64_encode('[hls-recorder] '.$sub)."?=", $msg, "Content-type: text/plain; charset=utf-8"))
 | |
| 				logger($loglevel, 'Unable to send notification E-mail');
 | |
| }
 | |
| 
 | |
| // Check requirements
 | |
| if (!function_exists('curl_init'))
 | |
|     logger(1, 'cURL is required but not available', 1, true);
 | |
| if (!function_exists('json_decode'))
 | |
|     logger(1, 'json_decode is required but not available', 1, true);
 | |
| 
 | |
| // Settings
 | |
| $config = isset($opts['c']) ? $opts['c'] : __DIR__.'/config.json';
 | |
| if (!file_exists($config))
 | |
|     logger(1, 'Config file not found: '.$config, 1, true);
 | |
| if (!$_set = @json_decode(@file_get_contents($config)))
 | |
|     logger(1, 'Unable to load or parse configuration file', 1, true);
 | |
| 
 | |
| // Check settings
 | |
| $_set_def = [
 | |
|     'rtmp' => '',
 | |
|     'recordhls' => false
 | |
| ];
 | |
| foreach ($_set_def AS $i => $v)
 | |
|     if (!isset($_set->{$i}))
 | |
|         $_set->{$i} = $v;
 | |
| 
 | |
| // Loop indefinitely
 | |
| while (true) :
 | |
| 
 | |
|     if ($api = @file_get_contents($_set->api.'/states'))
 | |
|         if ($api = @json_decode($api))
 | |
|             if (isset($api->repeat_to_local_nginx) && $api->repeat_to_local_nginx->type == 'connected')
 | |
|             {
 | |
|                 logger(1, 'Repeater seems to be connected');
 | |
| 
 | |
|                 $handle = curl_init($_set->hls);
 | |
|                 curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
 | |
|                 $response = curl_exec($handle);
 | |
|                 $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
 | |
|                 curl_close($handle);
 | |
|                 if ($httpCode == 200)
 | |
|                 {
 | |
|                     $output_directory = $_set->vod.'/vod-'.date('Ymd-His');
 | |
|                     $exitcode = 0;
 | |
| 
 | |
|                     if (@mkdir($output_directory))
 | |
|                     {
 | |
|                         logger(2, 'All checks passed, starting ffmpeg');
 | |
|                         notify('Recording', 'Restreamer API reported that repeating to local nginx is connected and the HLS endpoint is found. The HLS output is now being recorded. HLS URL is the following: '.$_set->hls.', Output directory is: '.$output_directory, 2);
 | |
|                         if ($_set->recordhls || !$_set->rtmp)
 | |
|                             exec('flock -n '.$_set->pid.' -c "ffmpeg -re -i '.$_set->hls.' -c copy '.$output_directory.'/index.m3u8 2> '.$output_directory.'/ffmpeg.log"', $output, $exitcode);
 | |
|                         else
 | |
|                             exec('flock -n '.$_set->pid.' -c "ffmpeg -re -i '.$_set->hls.' -c copy -start_number 0 -hls_time 10 -hls_list_size 0 -f hls '.$output_directory.'/index.m3u8 2> '.$output_directory.'/ffmpeg.log"', $output, $exitcode);
 | |
|                         logger(2, 'ffmpeg exited with code '.$exitcode);
 | |
|                         notify('Recording stopped', 'The FFMPEG process shut down with exit code: '.$exitcode, 2);
 | |
|                         if ($exitcode)
 | |
|                         {
 | |
|                             logger(3, 'Non-clean exit (expected), checking if output directory is empty');
 | |
|                             if (is_dir_empty($output_directory))
 | |
|                                 if (@rmdir($output_directory))
 | |
|                                     logger(4, 'Output directory removed');
 | |
|                                 else
 | |
| 				{
 | |
|                                     logger(4, 'Unable to remove output directory');
 | |
|                                     notify('Error', 'The FFMPEG process shut down with exit code '.$exitcode.' and the output directory is empty (nothing recorded). Output directory should have been removed automatically, but the process failed. Remove the output directory manually: '.$output_directory, 4);
 | |
| 				}
 | |
|                         }
 | |
|                     } else
 | |
|                         logger(3, 'Unable to create output directory');
 | |
|                 } else
 | |
|                     logger(2, 'HLS inaccessible, HTTP Code '.$httpCode);
 | |
| 
 | |
|             } else
 | |
|                 logger(1, 'Repeater not in connected state', 0);
 | |
|         else
 | |
|             logger(1, 'API response unreadable');
 | |
|     else
 | |
|         logger(1, 'API can not be accessed');
 | |
| 
 | |
|     sleep($_set->sleep);
 | |
| 
 | |
| endwhile;
 |