2014-06-04 21:37:21 +02:00
|
|
|
<?php
|
2016-12-16 21:49:07 +01:00
|
|
|
namespace AzuraCast\Radio\Frontend;
|
2014-06-04 21:37:21 +02:00
|
|
|
|
2016-11-22 06:09:18 +01:00
|
|
|
use App\Debug;
|
|
|
|
use App\Utilities;
|
2017-04-17 10:57:42 +02:00
|
|
|
use Doctrine\ORM\EntityManager;
|
|
|
|
use Entity;
|
2014-06-04 21:37:21 +02:00
|
|
|
|
2016-11-22 06:09:18 +01:00
|
|
|
class ShoutCast2 extends FrontendAbstract
|
2014-06-04 21:37:21 +02:00
|
|
|
{
|
2017-04-13 00:19:02 +02:00
|
|
|
protected $supports_mounts = true;
|
2016-05-06 10:57:34 +02:00
|
|
|
|
2014-06-05 08:48:36 +02:00
|
|
|
/* Process a nowplaying record. */
|
2017-01-24 01:17:50 +01:00
|
|
|
protected function _getNowPlaying(&$np)
|
2017-01-22 21:58:40 +01:00
|
|
|
{
|
2017-01-24 01:17:50 +01:00
|
|
|
$fe_config = (array)$this->station->frontend_config;
|
|
|
|
$radio_port = $fe_config['port'];
|
2014-06-05 08:48:36 +02:00
|
|
|
|
2017-05-31 17:47:19 +02:00
|
|
|
$np_url = 'http://'.(APP_INSIDE_DOCKER ? 'stations' : 'localhost').':' . $radio_port . '/statistics?json=1';
|
2017-01-24 01:17:50 +01:00
|
|
|
$return_raw = $this->getUrl($np_url);
|
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
if (empty($return_raw)) {
|
2017-01-24 01:17:50 +01:00
|
|
|
return false;
|
2017-01-24 01:35:16 +01:00
|
|
|
}
|
2017-01-24 01:17:50 +01:00
|
|
|
|
2017-05-16 09:46:43 +02:00
|
|
|
$current_data = json_decode($return_raw, true);
|
|
|
|
Debug::print_r($current_data);
|
2017-01-24 01:17:50 +01:00
|
|
|
|
2017-05-18 09:24:54 +02:00
|
|
|
$streams = count($current_data['streams']);
|
|
|
|
$u_list = 0;
|
|
|
|
$t_list = 0;
|
|
|
|
|
|
|
|
$em = $this->di['em'];
|
|
|
|
$mount_repo = $em->getRepository(Entity\StationMount::class);
|
|
|
|
$default_mount = $mount_repo->getDefaultMount($this->station);
|
|
|
|
|
|
|
|
foreach($current_data['streams'] as $stream) {
|
|
|
|
if ($stream['streampath'] === $default_mount->name) {
|
|
|
|
$song_data = $stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
$u_list += (int)$stream['uniquelisteners'];
|
|
|
|
$t_list += (int)$stream['currentlisteners'];
|
|
|
|
}
|
2017-01-24 01:17:50 +01:00
|
|
|
|
|
|
|
$np['meta']['status'] = 'online';
|
2017-05-16 09:46:43 +02:00
|
|
|
$np['meta']['bitrate'] = $song_data['bitrate'];
|
|
|
|
$np['meta']['format'] = $song_data['content'];
|
2017-01-24 01:17:50 +01:00
|
|
|
|
2017-05-16 09:46:43 +02:00
|
|
|
$np['current_song'] = $this->getSongFromString($song_data['songtitle'], '-');
|
2017-01-24 01:17:50 +01:00
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
$np['listeners'] = [
|
|
|
|
'current' => $this->getListenerCount($u_list, $t_list),
|
|
|
|
'unique' => $u_list,
|
|
|
|
'total' => $t_list,
|
|
|
|
];
|
2014-08-23 10:09:49 +02:00
|
|
|
|
2017-05-16 09:46:43 +02:00
|
|
|
// Attempt to fetch detailed listener information for better unique statistics.
|
2017-05-18 09:24:54 +02:00
|
|
|
$np['listeners']['clients'] = [];
|
|
|
|
|
|
|
|
for($i = 1; $i <= $streams; $i++) {
|
2017-05-31 17:47:19 +02:00
|
|
|
$listeners_url = 'http://'.(APP_INSIDE_DOCKER ? 'stations' : 'localhost').':' . $radio_port . '/admin.cgi?sid='.$i.'&mode=viewjson&page=3';
|
2017-05-18 09:24:54 +02:00
|
|
|
$return_raw = $this->getUrl($listeners_url, [
|
|
|
|
'basic_auth' => 'admin:'.$fe_config['admin_pw'],
|
|
|
|
]);
|
|
|
|
|
|
|
|
if (!empty($return_raw)) {
|
|
|
|
$listeners = json_decode($return_raw, true);
|
|
|
|
|
|
|
|
foreach((array)$listeners as $listener) {
|
|
|
|
$np['listeners']['clients'][] = [
|
|
|
|
'uid' => $listener['uid'],
|
|
|
|
'ip' => $listener['xff'] ?: $listener['hostname'],
|
|
|
|
'user_agent' => $listener['useragent'],
|
|
|
|
'connected_seconds' => $listener['connecttime'],
|
|
|
|
];
|
|
|
|
}
|
2017-05-16 09:46:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-23 10:09:49 +02:00
|
|
|
return true;
|
2014-06-05 08:48:36 +02:00
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
public function read()
|
2016-11-22 06:09:18 +01:00
|
|
|
{
|
2017-01-24 01:17:50 +01:00
|
|
|
$config = $this->_getConfig();
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
$this->station->frontend_config = $this->_loadFromConfig($config);
|
2017-01-24 01:35:16 +01:00
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
return true;
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function write()
|
|
|
|
{
|
|
|
|
$config = $this->_getDefaults();
|
|
|
|
|
|
|
|
$frontend_config = (array)$this->station->frontend_config;
|
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
if (!empty($frontend_config['port'])) {
|
2016-11-22 06:09:18 +01:00
|
|
|
$config['portbase'] = $frontend_config['port'];
|
2017-01-24 01:35:16 +01:00
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
if (!empty($frontend_config['source_pw'])) {
|
2016-11-22 06:09:18 +01:00
|
|
|
$config['password'] = $frontend_config['source_pw'];
|
2017-01-24 01:35:16 +01:00
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
if (!empty($frontend_config['admin_pw'])) {
|
2016-11-22 06:09:18 +01:00
|
|
|
$config['adminpassword'] = $frontend_config['admin_pw'];
|
2017-01-24 01:35:16 +01:00
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-05-24 01:18:27 +02:00
|
|
|
if (!empty($frontend_config['max_listeners'])) {
|
|
|
|
$config['maxuser'] = $frontend_config['max_listeners'];
|
|
|
|
}
|
|
|
|
|
2017-01-24 01:35:16 +01:00
|
|
|
if (!empty($frontend_config['custom_config'])) {
|
2016-11-22 06:09:18 +01:00
|
|
|
$custom_conf = $this->_processCustomConfig($frontend_config['custom_config']);
|
2017-01-24 01:35:16 +01:00
|
|
|
if (!empty($custom_conf)) {
|
2016-11-22 06:09:18 +01:00
|
|
|
$config = array_merge($config, $custom_conf);
|
2017-01-24 01:35:16 +01:00
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
2017-04-17 10:57:42 +02:00
|
|
|
$i = 0;
|
|
|
|
foreach ($this->station->mounts as $mount_row) {
|
|
|
|
$i++;
|
|
|
|
$config['streamid_'.$i] = $i;
|
|
|
|
$config['streampath_'.$i] = $mount_row->name;
|
|
|
|
|
|
|
|
if ($mount_row->relay_url) {
|
|
|
|
$config['streamrelayurl_'.$i] = $mount_row->relay_url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 06:09:18 +01:00
|
|
|
// Set any unset values back to the DB config.
|
|
|
|
$this->station->frontend_config = $this->_loadFromConfig($config);
|
|
|
|
|
|
|
|
$em = $this->di['em'];
|
|
|
|
$em->persist($this->station);
|
|
|
|
$em->flush();
|
|
|
|
|
|
|
|
$config_path = $this->station->getRadioConfigDir();
|
2017-01-24 01:35:16 +01:00
|
|
|
$sc_path = $config_path . '/sc_serv.conf';
|
2016-11-22 06:09:18 +01:00
|
|
|
|
|
|
|
$sc_file = '';
|
2017-01-24 01:35:16 +01:00
|
|
|
foreach ($config as $config_key => $config_value) {
|
|
|
|
$sc_file .= $config_key . '=' . str_replace("\n", "", $config_value) . "\n";
|
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
|
|
|
|
file_put_contents($sc_path, $sc_file);
|
|
|
|
}
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
/*
|
|
|
|
* Process Management
|
|
|
|
*/
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2016-12-13 00:01:28 +01:00
|
|
|
public function getCommand()
|
2016-11-22 06:09:18 +01:00
|
|
|
{
|
2017-06-12 22:29:03 +02:00
|
|
|
if ($binary = self::getBinary()) {
|
|
|
|
$config_path = $this->station->getRadioConfigDir();
|
|
|
|
$sc_config = $config_path . '/sc_serv.conf';
|
2016-11-22 06:09:18 +01:00
|
|
|
|
2017-06-12 22:29:03 +02:00
|
|
|
return $binary . ' ' . $sc_config;
|
|
|
|
} else {
|
|
|
|
return '/bin/false';
|
|
|
|
}
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getStreamUrl()
|
|
|
|
{
|
2017-04-17 10:57:42 +02:00
|
|
|
/** @var EntityManager */
|
|
|
|
$em = $this->di->get('em');
|
|
|
|
|
|
|
|
$mount_repo = $em->getRepository(Entity\StationMount::class);
|
|
|
|
$default_mount = $mount_repo->getDefaultMount($this->station);
|
|
|
|
|
|
|
|
$mount_name = ($default_mount instanceof Entity\StationMount) ? $default_mount->name : '/stream/1/';
|
|
|
|
|
|
|
|
return $this->getUrlForMount($mount_name);
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
public function getStreamUrls()
|
|
|
|
{
|
2017-04-17 10:57:42 +02:00
|
|
|
$urls = [];
|
|
|
|
foreach ($this->station->mounts as $mount) {
|
|
|
|
$urls[] = $this->getUrlForMount($mount->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $urls;
|
2017-01-24 01:17:50 +01:00
|
|
|
}
|
|
|
|
|
2016-11-22 06:09:18 +01:00
|
|
|
public function getUrlForMount($mount_name)
|
|
|
|
{
|
2017-01-24 01:35:16 +01:00
|
|
|
return $this->getPublicUrl() . $mount_name . '?' . time();
|
2017-01-24 01:17:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getAdminUrl()
|
|
|
|
{
|
2017-01-24 01:35:16 +01:00
|
|
|
return $this->getPublicUrl() . '/admin.cgi';
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configuration
|
|
|
|
*/
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
protected function _getConfig()
|
2016-11-22 06:09:18 +01:00
|
|
|
{
|
2017-01-24 01:17:50 +01:00
|
|
|
$config_dir = $this->station->getRadioConfigDir();
|
2017-01-24 01:35:16 +01:00
|
|
|
$config = @parse_ini_file($config_dir . '/sc_serv.conf', false, INI_SCANNER_RAW);
|
2017-01-24 01:17:50 +01:00
|
|
|
|
|
|
|
return $config;
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
protected function _loadFromConfig($config)
|
2016-11-22 06:09:18 +01:00
|
|
|
{
|
2017-01-24 01:17:50 +01:00
|
|
|
return [
|
|
|
|
'port' => $config['portbase'],
|
|
|
|
'source_pw' => $config['password'],
|
|
|
|
'admin_pw' => $config['adminpassword'],
|
2017-05-24 01:18:27 +02:00
|
|
|
'max_listeners' => $config['maxuser'],
|
2017-01-24 01:17:50 +01:00
|
|
|
];
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
protected function _getDefaults()
|
2016-11-22 06:09:18 +01:00
|
|
|
{
|
2017-01-24 01:17:50 +01:00
|
|
|
$config_path = $this->station->getRadioConfigDir();
|
2017-01-22 21:58:40 +01:00
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
$defaults = [
|
2017-01-24 01:35:16 +01:00
|
|
|
'password' => Utilities::generatePassword(),
|
2017-01-24 01:17:50 +01:00
|
|
|
'adminpassword' => Utilities::generatePassword(),
|
2017-01-24 01:35:16 +01:00
|
|
|
'logfile' => $config_path . '/sc_serv.log',
|
|
|
|
'w3clog' => $config_path . '/sc_w3c.log',
|
|
|
|
'banfile' => $config_path . '/sc_serv.ban',
|
|
|
|
'ripfile' => $config_path . '/sc_serv.rip',
|
2017-05-24 01:18:27 +02:00
|
|
|
'maxuser' => 250,
|
2017-01-24 01:35:16 +01:00
|
|
|
'portbase' => $this->_getRadioPort(),
|
2017-04-23 03:48:19 +02:00
|
|
|
'requirestreamconfigs' => 1,
|
2016-11-22 06:09:18 +01:00
|
|
|
];
|
|
|
|
|
2017-01-24 01:17:50 +01:00
|
|
|
return $defaults;
|
2016-11-22 06:09:18 +01:00
|
|
|
}
|
2017-05-19 08:38:17 +02:00
|
|
|
|
2017-06-12 22:29:03 +02:00
|
|
|
public static function getBinary()
|
2017-05-19 08:38:17 +02:00
|
|
|
{
|
2017-06-12 22:29:03 +02:00
|
|
|
$new_path = realpath(APP_INCLUDE_ROOT . '/..') . '/servers/shoutcast2/sc_serv';
|
|
|
|
|
|
|
|
if (APP_INSIDE_DOCKER || file_exists($new_path)) {
|
|
|
|
return $new_path;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-19 08:38:17 +02:00
|
|
|
}
|
2014-05-02 10:13:40 +02:00
|
|
|
}
|