Merge branch 'devel' of dev.sourcefabric.org:airtime into devel
Conflicts: python_apps/media-monitor/airtimefilemonitor/airtimeprocessevent.py
This commit is contained in:
commit
2786d40db8
|
@ -122,6 +122,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$file_base_name = substr($file_base_name, 1);
|
||||
header('Content-Disposition: attachment; filename="'.$file_base_name.'"');
|
||||
}
|
||||
$logger->info("Sending $filepath");
|
||||
header("Content-Length: " . filesize($filepath));
|
||||
|
||||
// !! binary mode !!
|
||||
|
@ -539,6 +540,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$filepath = $md['MDATA_KEY_FILEPATH'];
|
||||
$filepath = str_replace("\\", "", $filepath);
|
||||
$files = Application_Model_StoredFile::RecallByPartialFilepath($filepath);
|
||||
|
||||
foreach($files as $file){
|
||||
$file->delete();
|
||||
}
|
||||
|
@ -692,7 +694,7 @@ class ApiController extends Zend_Controller_Action
|
|||
$remoteAddr = $_SERVER['REMOTE_ADDR'];
|
||||
Logging::log("Registered Component: ".$component."@".$remoteAddr);
|
||||
|
||||
Application_Model_Component::Register($component, $remoteAddr);
|
||||
Application_Model_ServiceRegister::Register($component, $remoteAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,13 @@ class DashboardController extends Zend_Controller_Action
|
|||
$baseUrl = $request->getBaseUrl();
|
||||
$this->view->headLink()->appendStylesheet($baseUrl.'/js/jplayer/skin/jplayer.blue.monday.css');
|
||||
$this->_helper->layout->setLayout('bare');
|
||||
|
||||
$logo = Application_Model_Preference::GetStationLogo();
|
||||
if($logo){
|
||||
$this->view->logo = "data:image/png;base64,$logo";
|
||||
} else {
|
||||
$this->view->logo = "$baseUrl/css/images/airtime_logo_jp.png";
|
||||
}
|
||||
}
|
||||
|
||||
public function helpAction()
|
||||
|
|
|
@ -219,6 +219,7 @@ class LibraryController extends Zend_Controller_Action
|
|||
Logging::log($data['MDATA_KEY_FILEPATH']);
|
||||
Application_Model_RabbitMq::SendMessageToMediaMonitor("md_update", $data);
|
||||
|
||||
|
||||
$this->_helper->redirector('index');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,6 +281,7 @@ class Application_Model_MusicDir {
|
|||
}
|
||||
|
||||
public static function removeWatchedDir($p_dir){
|
||||
|
||||
$real_path = realpath($p_dir)."/";
|
||||
if($real_path != "/"){
|
||||
$p_dir = $real_path;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?php
|
||||
class Application_Model_Component {
|
||||
class Application_Model_ServiceRegister {
|
||||
|
||||
public static function Register($p_componentName, $p_ipAddress){
|
||||
|
|
@ -597,7 +597,7 @@ class Application_Model_StoredFile {
|
|||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public static function searchFilesForPlaylistBuilder($datatables) {
|
||||
global $CC_CONFIG;
|
||||
|
||||
|
@ -751,7 +751,7 @@ class Application_Model_StoredFile {
|
|||
$chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0;
|
||||
$chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0;
|
||||
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : '';
|
||||
Logging::log(__FILE__.':uploadFile(): filename='.$fileName);
|
||||
Logging::log(__FILE__.":uploadFile(): filename=$fileName to $p_targetDir");
|
||||
// Clean the fileName for security reasons
|
||||
//this needs fixing for songs not in ascii.
|
||||
//$fileName = preg_replace('/[^\w\._]+/', '', $fileName);
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skeleton subclass for representing a row from the 'cc_component' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
* @package propel.generator.airtime
|
||||
*/
|
||||
class CcComponent extends BaseCcComponent {
|
||||
|
||||
} // CcComponent
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'cc_component' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
* @package propel.generator.airtime
|
||||
*/
|
||||
class CcComponentPeer extends BaseCcComponentPeer {
|
||||
|
||||
} // CcComponentPeer
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Skeleton subclass for performing query and update operations on the 'cc_component' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* You should add additional methods to this class to meet the
|
||||
* application requirements. This class will only be generated as
|
||||
* long as it does not already exist in the output directory.
|
||||
*
|
||||
* @package propel.generator.airtime
|
||||
*/
|
||||
class CcComponentQuery extends BaseCcComponentQuery {
|
||||
|
||||
} // CcComponentQuery
|
|
@ -42,11 +42,11 @@ $(document).ready(function(){
|
|||
?>
|
||||
});
|
||||
</script>
|
||||
<div class="jp-logo"></div>
|
||||
<div class="jp-logo"><img id="logo-img" onload='resizeToMaxHeight(this, 67);' src="<?php echo $this->logo ?>" /></div>
|
||||
<div class="jp-stream">
|
||||
<div class="jp-stream-text">Select stream:</div>
|
||||
|
||||
<form id="form1" method="post" action="">
|
||||
|
||||
<select id="combo-box">
|
||||
<?php
|
||||
foreach($ids as $id) {
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
|
||||
<dd id="Logo-element">
|
||||
<?php if($this->element->getView()->logoImg){?>
|
||||
<div id="Logo-img-container"><img id="logo-img" onload='resizeImg(this);' src="data:image/png;base64,<?php echo $this->element->getView()->logoImg ?>" /></div>
|
||||
<div id="Logo-img-container"><img id="logo-img" onload='resizeImg(this, 450, 450);' src="data:image/png;base64,<?php echo $this->element->getView()->logoImg ?>" /></div>
|
||||
<?php }?>
|
||||
|
||||
<?php echo $this->element->getElement('Logo') ?>
|
||||
|
@ -176,4 +176,4 @@
|
|||
<?php }?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
</dt>
|
||||
<dd id="Logo-element" class="block-display clearfix">
|
||||
<?php if($this->element->getView()->logoImg){?>
|
||||
<div id="Logo-img-container"><img id="logo-img" onload='resizeImg(this);' src="data:image/png;base64,<?php echo $this->element->getView()->logoImg ?>" /></div>
|
||||
<div id="Logo-img-container"><img id="logo-img" onload='resizeImg(this, 450, 450);' src="data:image/png;base64,<?php echo $this->element->getView()->logoImg ?>" /></div>
|
||||
<?php }?>
|
||||
|
||||
<?php echo $this->element->getElement('Logo') ?>
|
||||
|
@ -175,4 +175,4 @@
|
|||
<a id="link_to_terms_and_condition" href="http://www.sourcefabric.org/en/about/policy/" onclick="window.open(this.href); return false;">Terms and Conditions</a>
|
||||
<?php }?>
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
|
|
|
@ -222,3 +222,41 @@ function audioPreview(filename, elemID){
|
|||
|
||||
$('#'+elemID+' div.list-item-container a span').attr("class", "ui-icon ui-icon-pause");
|
||||
}
|
||||
|
||||
function resizeImg(ele, targetWidth, targetHeight){
|
||||
var img = $(ele);
|
||||
|
||||
var width = ele.width;
|
||||
var height = ele.height;
|
||||
|
||||
// resize img proportionaly
|
||||
if( width > height && width > targetWidth){
|
||||
var ratio = targetWidth/width;
|
||||
img.css("width", targetHeight+"px");
|
||||
var newHeight = height * ratio;
|
||||
img.css("height", newHeight+"px");
|
||||
}else if( width < height && height > targetHeight){
|
||||
var ratio = targetHeight/height;
|
||||
img.css("height", targetHeight+"px");
|
||||
var newWidth = width * ratio;
|
||||
img.css("width", newWidth+"px");
|
||||
}else if( width == height && width > targetWidth){
|
||||
img.css("height", targetHeight+"px");
|
||||
img.css("width", targetWidth+"px" );
|
||||
}
|
||||
}
|
||||
|
||||
function resizeToMaxHeight(ele, targetHeight){
|
||||
var img = $(ele);
|
||||
|
||||
var width = ele.width;
|
||||
var height = ele.height;
|
||||
|
||||
// resize img proportionaly
|
||||
if( height > targetHeight){
|
||||
var ratio = targetHeight/height;
|
||||
img.css("height", targetHeight+"px");
|
||||
var newWidth = width * ratio;
|
||||
img.css("width", newWidth+"px");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,27 +102,25 @@ $(document).ready(function(){
|
|||
});
|
||||
});
|
||||
|
||||
function resizeImg(ele){
|
||||
|
||||
function resizeImg(ele, targetWidth, targetHeight){
|
||||
var img = $(ele);
|
||||
|
||||
var width = ele.width;
|
||||
var height = ele.height;
|
||||
|
||||
// resize img proportionaly
|
||||
if( width > height && width > 430){
|
||||
var ratio = 430/width;
|
||||
img.css("width", "430px");
|
||||
if( width > height && width > targetWidth){
|
||||
var ratio = targetWidth/width;
|
||||
img.css("width", targetHeight+"px");
|
||||
var newHeight = height * ratio;
|
||||
img.css("height", newHeight );
|
||||
|
||||
}else if( width < height && height > 430){
|
||||
var ratio = 430/height;
|
||||
img.css("height", "430px");
|
||||
img.css("height", newHeight);
|
||||
}else if( width < height && height > targetHeight){
|
||||
var ratio = targetHeight/height;
|
||||
img.css("height", targetHeight+"px");
|
||||
var newWidth = width * ratio;
|
||||
img.css("width", newWidth );
|
||||
}else if( width == height && width > 430){
|
||||
img.css("height", "430px");
|
||||
img.css("width", "430px" );
|
||||
}
|
||||
}
|
||||
img.css("width", newWidth);
|
||||
}else if( width == height && width > targetWidth){
|
||||
img.css("height", targetHeight+"px");
|
||||
img.css("width", targetWidth+"px" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,31 +10,6 @@ function showErrorSections() {
|
|||
}
|
||||
}
|
||||
|
||||
function resizeImg(ele){
|
||||
var img = $(ele);
|
||||
|
||||
var width = ele.width;
|
||||
var height = ele.height;
|
||||
|
||||
// resize img proportionaly
|
||||
if( width > height && width > 450){
|
||||
var ratio = 450/width;
|
||||
img.css("width", "450px");
|
||||
var newHeight = height * ratio;
|
||||
img.css("height", newHeight );
|
||||
|
||||
}else if( width < height && height > 450){
|
||||
var ratio = 450/height;
|
||||
img.css("height", "450px");
|
||||
var newWidth = width * ratio;
|
||||
img.css("width", newWidth );
|
||||
}else if( width == height && width > 450){
|
||||
img.css("height", "450px");
|
||||
img.css("width", "450px" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var form = $("form");
|
||||
|
||||
|
|
|
@ -38,14 +38,25 @@
|
|||
text-shadow: 0px -1px 1px #000;
|
||||
}
|
||||
|
||||
.jp-logo {
|
||||
.jp-logo{
|
||||
width:400px;
|
||||
height: 67px;
|
||||
background:#282828 url(../../../css/images/airtime_logo_jp.png) no-repeat 120px 14px;
|
||||
/* background:#282828 url(../../../css/images/airtime_logo_jp.png) no-repeat 120px 14px;
|
||||
background: url(../../../css/images/airtime_logo_jp.png) no-repeat 120px 14px, -moz-radial-gradient(200px 0px, circle cover, rgba(70,70,70,1) 0%, rgba(40,40,40,1) 90%);
|
||||
background: url(../../../css/images/airtime_logo_jp.png) no-repeat 120px 14px, -webkit-radial-gradient(170px 20px, rgba(70,70,70,1) 0%,rgba(40,40,40,1) 70%);
|
||||
background: url(../../../css/images/airtime_logo_jp.png) no-repeat 120px 14px, -webkit-radial-gradient(170px 20px, rgba(70,70,70,1) 0%,rgba(40,40,40,1) 70%); */
|
||||
background:#282828 no-repeat 120px 14px;
|
||||
background: no-repeat 120px 14px, -moz-radial-gradient(200px 0px, circle cover, rgba(70,70,70,1) 0%, rgba(40,40,40,1) 90%);
|
||||
background: no-repeat 120px 14px, -webkit-radial-gradient(170px 20px, rgba(70,70,70,1) 0%,rgba(40,40,40,1) 70%);
|
||||
display:block;
|
||||
}
|
||||
|
||||
.jp-logo img{
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
}
|
||||
|
||||
.jp-stream {
|
||||
height: 27px;
|
||||
display:block;
|
||||
|
|
|
@ -129,9 +129,9 @@ AirtimeInstall::InstallStorageDirectory();
|
|||
|
||||
if ($db_install) {
|
||||
if($newInstall) {
|
||||
// This is called with "system" so that we can pass in a parameter. See the file itself
|
||||
// This is called with "passthru" so that we can pass in a parameter. See the file itself
|
||||
// for why we need to do this.
|
||||
system('php '.__DIR__.'/airtime-db-install.php y');
|
||||
passthru('php '.__DIR__.'/airtime-db-install.php y');
|
||||
AirtimeInstall::DbConnect(true);
|
||||
} else {
|
||||
require_once('airtime-db-install.php');
|
||||
|
|
|
@ -677,7 +677,10 @@ class Airtime190Upgrade{
|
|||
->findOne();
|
||||
|
||||
/* Handle Database Changes. */
|
||||
$stor_dir = realpath($values['general']['base_files_dir']."/stor")."/";
|
||||
|
||||
$pi = pathinfo($values['general']['base_files_dir']);
|
||||
$stor_dir = $pi["dirname"].DIRECTORY_SEPARATOR.$pi["basename"].DIRECTORY_SEPARATOR."stor".DIRECTORY_SEPARATOR;
|
||||
|
||||
echo "* Inserting stor directory location $stor_dir into music_dirs table".PHP_EOL;
|
||||
$propel_stor_dir->setDirectory($stor_dir);
|
||||
$propel_stor_dir->save();
|
||||
|
@ -763,6 +766,7 @@ exec("svc -dx /etc/service/pypo-liquidsoap/log");
|
|||
exec("svc -dx /etc/service/recorder");
|
||||
exec("svc -dx /etc/service/recorder/log");
|
||||
exec("killall supervise");
|
||||
exec("killall liquidsoap");
|
||||
|
||||
$pathnames = array("/usr/bin/airtime-pypo-start",
|
||||
"/usr/bin/airtime-pypo-stop",
|
||||
|
@ -819,6 +823,7 @@ AirtimeInstall::SetUniqueId();
|
|||
AirtimeInstall::SetImportTimestamp();
|
||||
|
||||
AirtimeIni::CreateMonitFile();
|
||||
exec("/etc/init.d/monit start");
|
||||
|
||||
AirtimeInstall::CreateSymlinksToUtils();
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class UpgradeCommon{
|
|||
}
|
||||
}
|
||||
|
||||
$default_suffix = "200";
|
||||
$default_suffix = CONF_BACKUP_SUFFIX;
|
||||
self::CreateIniFiles($default_suffix);
|
||||
self::MergeConfigFiles($configFiles, $suffix);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
const VERSION_NUMBER = "2.0.0";
|
||||
const CONF_BACKUP_SUFFIX = "200";
|
||||
|
||||
set_include_path(__DIR__.'/../../../airtime_mvc/library' . PATH_SEPARATOR . get_include_path());
|
||||
set_include_path(__DIR__.'/../../../airtime_mvc/library/pear' . PATH_SEPARATOR . get_include_path());
|
||||
|
@ -28,6 +29,8 @@ Propel::init(__DIR__."/../../../airtime_mvc/application/configs/airtime-conf.php
|
|||
|
||||
require_once 'UpgradeCommon.php';
|
||||
|
||||
$bypassMigrations=array('20110312121200', '20110331111708', '20110402164819', '20110406182005', '20110629143017', '20110711161043', '20110713161043');
|
||||
$targetMigration='20110925171256';
|
||||
|
||||
/* All functions other than start() should be marked as
|
||||
* private.
|
||||
|
@ -39,14 +42,14 @@ class AirtimeDatabaseUpgrade{
|
|||
}
|
||||
|
||||
private static function doDbMigration(){
|
||||
global $bypassMigrations, $targetMigration;
|
||||
if(UpgradeCommon::DbTableExists('doctrine_migration_versions') === false) {
|
||||
$migrations = array('20110312121200', '20110331111708', '20110402164819', '20110406182005', '20110629143017', '20110711161043', '20110713161043');
|
||||
foreach($migrations as $migration) {
|
||||
foreach($bypassMigrations as $migration) {
|
||||
UpgradeCommon::BypassMigrations(__DIR__, $migration);
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeCommon::MigrateTablesToVersion(__DIR__, '20110925171256');
|
||||
UpgradeCommon::MigrateTablesToVersion(__DIR__, $targetMigration);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +73,7 @@ class AirtimeConfigFileUpgrade{
|
|||
* 3 classes. For example, there may be stray files scattered throughout
|
||||
* the filesystem that we don't need anymore. Put the functions to clean
|
||||
* those out into this class. */
|
||||
class AirtimeMiscUpgrade{1
|
||||
class AirtimeMiscUpgrade{
|
||||
|
||||
public static function start(){
|
||||
}
|
||||
|
|
|
@ -40,10 +40,13 @@ def to_unicode(obj, encoding='utf-8'):
|
|||
return obj
|
||||
|
||||
def encode_to(obj, encoding='utf-8'):
|
||||
if isinstance(obj, basestring):
|
||||
if not isinstance(obj, str):
|
||||
obj = obj.encode(encoding)
|
||||
if isinstance(obj, unicode):
|
||||
obj = obj.encode(encoding)
|
||||
return obj
|
||||
|
||||
def convert_dict_value_to_utf8(md):
|
||||
#list comprehension to convert all values of md to utf-8
|
||||
return dict([(item[0], encode_to(item[1], "utf-8")) for item in md.items()])
|
||||
|
||||
class ApiClientInterface:
|
||||
|
||||
|
@ -411,7 +414,9 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_media_url"])
|
||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||
url = url.replace("%%mode%%", mode)
|
||||
|
||||
|
||||
md = convert_dict_value_to_utf8(md)
|
||||
|
||||
data = urllib.urlencode(md)
|
||||
req = urllib2.Request(url, data)
|
||||
|
||||
|
@ -437,7 +442,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
|
||||
except Exception, e:
|
||||
response = None
|
||||
logger.error("Exception with filepath %s: %s", md['MDATA_KEY_FILEPATH'], e)
|
||||
logger.error("Exception with file %s: %s", md, e)
|
||||
|
||||
return response
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,7 +0,0 @@
|
|||
|
||||
SUBDIRS = tests
|
||||
DISTFILES = $(wildcard *.in) Makefile ask-liquidsoap.rb ask-liquidsoap.pl \
|
||||
$(wildcard *.liq) extract-replaygain
|
||||
|
||||
top_srcdir = ..
|
||||
include $(top_srcdir)/Makefile.rules
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict ;
|
||||
use Net::Telnet ;
|
||||
|
||||
my $telnet = new Net::Telnet ( Timeout=>10, Errmode=>'die', Port=>1234) ;
|
||||
$telnet->open('localhost') ;
|
||||
|
||||
die "Usage: $0 <command>\n" unless @ARGV ;
|
||||
$telnet->print($ARGV[0]) ;
|
||||
my ($output,$end) = $telnet->waitfor('/END$/') ;
|
||||
print $output;
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'net/telnet'
|
||||
|
||||
liq_host = "localhost"
|
||||
liq_port = 1234
|
||||
|
||||
conn = Net::Telnet::new("Host" => liq_host, "Port" => liq_port)
|
||||
|
||||
conn.puts(ARGV[0])
|
||||
conn.waitfor("Match" => /^END$/) do |data|
|
||||
puts data.sub(/\nEND\n/,"")
|
||||
end
|
|
@ -1,13 +1,5 @@
|
|||
# Decoders, enabled when the binary is detected and the os is not Win32.
|
||||
|
||||
# Get_mime is not always defined
|
||||
# so we define a default in this case..
|
||||
my_get_mime = fun (_) -> ""
|
||||
%ifdef get_mime
|
||||
my_get_mime = get_mime
|
||||
%endif
|
||||
get_mime = my_get_mime
|
||||
|
||||
%ifdef add_decoder
|
||||
# Enable external FLAC decoders. Requires flac binary
|
||||
# in the path for audio decoding and metaflac binary for
|
||||
|
@ -164,6 +156,7 @@ end
|
|||
# Standard function for displaying metadata.
|
||||
# Shows artist and title, using "Unknown" when a field is empty.
|
||||
# @param m Metadata packet to be displayed.
|
||||
# @category String
|
||||
def string_of_metadata(m)
|
||||
artist = m["artist"]
|
||||
title = m["title"]
|
||||
|
@ -177,6 +170,7 @@ end
|
|||
# @param ~position Position of the text (top|middle|bottom).
|
||||
# @param ~font Font used (xfontsel is your friend...)
|
||||
# @param ~display Function used to display a metadata packet.
|
||||
# @category Source / Track Processing
|
||||
def osd_metadata(~color="green",~position="top",
|
||||
~font="-*-courier-*-r-*-*-*-240-*-*-*-*-*-*",
|
||||
~display=string_of_metadata,
|
||||
|
@ -195,6 +189,7 @@ end
|
|||
# @param ~time Timeout in milliseconds.
|
||||
# @param ~display Function used to display a metadata packet.
|
||||
# @param ~title Title of the notification message.
|
||||
# @category Source / Track Processing
|
||||
def notify_metadata(~urgency="low",~icon="stock_smiley-22",~time=3000,
|
||||
~display=string_of_metadata,
|
||||
~title="Liquidsoap: new track",s)
|
||||
|
@ -211,6 +206,7 @@ end
|
|||
# @param ~restart_on_error restart on exit with error.
|
||||
# @param ~buffer Duration of the pre-buffered data.
|
||||
# @param ~max Maximum duration of the buffered data.
|
||||
# @category Source / Input
|
||||
def input.mplayer(~id="input.mplayer",
|
||||
~restart=true,~restart_on_error=false,
|
||||
~buffer=0.2,~max=10.,s) =
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict ;
|
||||
|
||||
my $file = $ARGV[0] || die ;
|
||||
|
||||
sub test_mime {
|
||||
my $file = shift ;
|
||||
if (`which file`) {
|
||||
return `file -b --mime-type "$file"`;
|
||||
}
|
||||
}
|
||||
|
||||
if (($file =~ /\.mp3$/i) || (test_mime($file) =~ /audio\/mpeg/)) {
|
||||
|
||||
if (`which mp3gain`) {
|
||||
|
||||
my $out = `mp3gain -q "$file" 2> /dev/null` ;
|
||||
$out =~ /Recommended "Track" dB change: (.*)$/m || die ;
|
||||
print "$1 dB\n" ;
|
||||
|
||||
} else {
|
||||
|
||||
print STDERR "Cannot find mp3gain binary!\n";
|
||||
|
||||
}
|
||||
|
||||
} elsif (($file =~ /\.ogg$/i) || (test_mime($file) =~ /application\/ogg/)) {
|
||||
|
||||
if ((`which vorbisgain`) && (`which ogginfo`)) {
|
||||
|
||||
system("vorbisgain -q -f \"$file\" 2>/dev/null >/dev/null") ;
|
||||
my $info = `ogginfo "$file"` ;
|
||||
$info =~ /REPLAYGAIN_TRACK_GAIN=(.*) dB/ || die ;
|
||||
print "$1 dB\n" ;
|
||||
|
||||
} else {
|
||||
|
||||
print STDERR "Cannot find vorbisgain or ogginfo!\n";
|
||||
|
||||
}
|
||||
|
||||
} elsif (($file =~ /\.flac$/i) || (test_mime($file) =~ /audio\/x-flac/)) {
|
||||
|
||||
if (`which metaflac`) {
|
||||
|
||||
my $info = `metaflac --show-tag=REPLAYGAIN_TRACK_GAIN "$file"` ;
|
||||
$info =~ /REPLAYGAIN_TRACK_GAIN=(.*) dB/;
|
||||
if (defined($1)) {
|
||||
|
||||
print "$1 dB\n" ;
|
||||
|
||||
} else {
|
||||
|
||||
system("metaflac --add-replay-gain \"$file\" \
|
||||
2>/dev/null >/dev/null") ;
|
||||
$info = `metaflac --show-tag=REPLAYGAIN_TRACK_GAIN "$file"` ;
|
||||
$info =~ /REPLAYGAIN_TRACK_GAIN=(.*) dB/ || die "Error in $file" ;
|
||||
print "$1 dB\n" ;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
print STDERR "Cannot find metaflac!\n";
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
print STDERR "File format not supported...\n";
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
# Set of HTTP utils.
|
||||
|
||||
%include "http_codes.liq"
|
||||
|
||||
# Create a HTTP response string
|
||||
# @category Interaction
|
||||
# @param ~protocol HTTP protocol used.
|
||||
# @param ~code Response code.
|
||||
# @param ~headers Response headers.
|
||||
# @param ~data Response data
|
||||
def http_response(~protocol="HTTP/1.1",
|
||||
~code=200,
|
||||
~headers=[],
|
||||
~data="") =
|
||||
status = http_codes[string_of(code)]
|
||||
# Set content-length if needed and not set by the
|
||||
# user.
|
||||
headers =
|
||||
if data != "" and
|
||||
not list.mem_assoc("Content-Length",headers)
|
||||
then
|
||||
list.append([("Content-Length",
|
||||
"#{string.length(data)}")],
|
||||
headers)
|
||||
else
|
||||
headers
|
||||
end
|
||||
headers = list.map(fun (x) -> "#{fst(x)}: #{snd(x)}",headers)
|
||||
headers = string.concat(separator="\r\n",headers)
|
||||
# If no headers are provided, we should avoid
|
||||
# having an empty line for them. Therefore, we also
|
||||
# conditionally add the final \r\n here.
|
||||
headers =
|
||||
if headers != "" then
|
||||
"#{headers}\r\n"
|
||||
else
|
||||
headers
|
||||
end
|
||||
"#{protocol} #{code} #{status}\r\n\
|
||||
#{headers}\
|
||||
\r\n\
|
||||
#{data}"
|
||||
end
|
|
@ -0,0 +1,304 @@
|
|||
# List of HTTP codes. Stolen from en.wikipedia.org..
|
||||
|
||||
# List of HTTP response codes and statuses.
|
||||
# @category Interaction
|
||||
def http_codes = [
|
||||
("100","Continue"),
|
||||
#This means that the server has received the request headers, and that the client
|
||||
#should proceed to send the request body (in the case of a request for which a
|
||||
#body needs to be sent; for example, a POST request). If the request body is
|
||||
#large, sending it to a server when a request has already been rejected based
|
||||
#upon inappropriate headers is inefficient. To have a server check if the request
|
||||
#could be accepted based on the request's headers alone, a client must send
|
||||
#Expect: 100-continue as a header in its initial request and check if a 100
|
||||
#Continue status code is received in response before continuing (or receive 417
|
||||
#Expectation Failed and not continue).
|
||||
|
||||
("101","Switching Protocols"),
|
||||
#This means the requester has asked the server to switch protocols and the server
|
||||
#is acknowledging that it will do so.
|
||||
|
||||
("102","Processing"),
|
||||
#As a WebDAV request may contain many sub-requests involving file operations, it
|
||||
#may take a long time to complete the request. This code indicates that the
|
||||
#server has received and is processing the request, but no response is available
|
||||
#yet. This prevents the client from timing out and assuming the request was
|
||||
#lost.
|
||||
|
||||
("122","Request-URI too long"),
|
||||
#This is a non-standard IE7-only code which means the URI is longer than a
|
||||
#maximum of 2083 characters. (See code 414.),
|
||||
|
||||
#2xx Success
|
||||
#This class of status codes indicates the action requested by the client was
|
||||
#received, understood, accepted and processed successfully.
|
||||
|
||||
("200","OK"),
|
||||
#Standard response for successful HTTP requests. The actual response will depend
|
||||
#on the request method used. In a GET request, the response will contain an
|
||||
#entity corresponding to the requested resource. In a POST request the response
|
||||
#will contain an entity describing or containing the result of the action.
|
||||
|
||||
("201","Created"),
|
||||
#The request has been fulfilled and resulted in a new resource being created.
|
||||
|
||||
("202","Accepted"),
|
||||
#The request has been accepted for processing, but the processing has not been
|
||||
#completed. The request might or might not eventually be acted upon, as it might
|
||||
#be disallowed when processing actually takes place.
|
||||
|
||||
("203","Non-Authoritative Information"),
|
||||
#The server successfully processed the request, but is returning information that
|
||||
#may be from another source.
|
||||
|
||||
("204","No Content"),
|
||||
#The server successfully processed the request, but is not returning any
|
||||
#content.
|
||||
|
||||
("205","Reset Content"),
|
||||
#The server successfully processed the request, but is not returning any content.
|
||||
#Unlike a 204 response, this response requires that the requester reset the
|
||||
#document view.
|
||||
|
||||
("206","Partial Content"),
|
||||
#The server is delivering only part of the resource due to a range header sent by
|
||||
#the client. The range header is used by tools like wget to enable resuming of
|
||||
#interrupted downloads, or split a download into multiple simultaneous
|
||||
#streams.
|
||||
|
||||
("207","Multi-Status"),
|
||||
#The message body that follows is an XML message and can contain a number of
|
||||
#separate response codes, depending on how many sub-requests were made.
|
||||
|
||||
("226","IM Used"),
|
||||
#The server has fulfilled a GET request for the resource, and the response is a
|
||||
#representation of the result of one or more instance-manipulations applied to
|
||||
#the current instance.
|
||||
|
||||
#3xx Redirection
|
||||
#The client must take additional action to complete the request.
|
||||
#This class of status code indicates that further action needs to be taken by the
|
||||
#user agent in order to fulfil the request. The action required may be carried
|
||||
#out by the user agent without interaction with the user if and only if the
|
||||
#method used in the second request is GET or HEAD. A user agent should not
|
||||
#automatically redirect a request more than five times, since such redirections
|
||||
#usually indicate an infinite loop.
|
||||
|
||||
("300","Multiple Choices"),
|
||||
#Indicates multiple options for the resource that the client may follow. It, for
|
||||
#instance, could be used to present different format options for video, list
|
||||
#files with different extensions, or word sense disambiguation.
|
||||
|
||||
("301","Moved Permanently"),
|
||||
#This and all future requests should be directed to the given URI.
|
||||
|
||||
("302","Found"),
|
||||
#This is an example of industrial practice contradicting the standard.
|
||||
#HTTP/1.0 specification (RFC 1945) required the client to perform a temporary
|
||||
#redirect (the original describing phrase was "Moved Temporarily"), but
|
||||
#popular browsers implemented 302 with the functionality of a 303 See Other.
|
||||
#Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the
|
||||
#two behaviours. However, the majority of Web applications and frameworks
|
||||
#still[as of?] use the 302 status code as if it were the 303.[citation needed]
|
||||
|
||||
("303","See Other"),
|
||||
#The response to the request can be found under another URI using a GET method.
|
||||
#When received in response to a POST (or PUT/DELETE), it should be assumed that
|
||||
#the server has received the data and the redirect should be issued with a
|
||||
#separate GET message.
|
||||
|
||||
("304","Not Modified"),
|
||||
#Indicates the resource has not been modified since last requested. Typically,
|
||||
#the HTTP client provides a header like the If-Modified-Since header to provide a
|
||||
#time against which to compare. Using this saves bandwidth and reprocessing on
|
||||
#both the server and client, as only the header data must be sent and received in
|
||||
#comparison to the entirety of the page being re-processed by the server, then
|
||||
#sent again using more bandwidth of the server and client.
|
||||
|
||||
("305","Use Proxy"),
|
||||
#Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly
|
||||
#handle responses with this status code, primarily for security reasons.
|
||||
|
||||
("306","Switch Proxy"),
|
||||
#No longer used.
|
||||
|
||||
("307","Temporary Redirect"),
|
||||
#In this occasion, the request should be repeated with another URI, but future
|
||||
#requests can still use the original URI. In contrast to 303, the request
|
||||
#method should not be changed when reissuing the original request. For instance,
|
||||
#a POST request must be repeated using another POST request.
|
||||
|
||||
#4xx Client Error
|
||||
#The 4xx class of status code is intended for cases in which the client seems to
|
||||
#have erred. Except when responding to a HEAD request, the server should include
|
||||
#an entity containing an explanation of the error situation, and whether it is a
|
||||
#temporary or permanent condition. These status codes are applicable to any
|
||||
#request method. User agents should display any included entity to the user.
|
||||
#These are typically the most common error codes encountered while online.
|
||||
|
||||
("400","Bad Request"),
|
||||
#The request cannot be fulfilled due to bad syntax.
|
||||
|
||||
("401","Unauthorized"),
|
||||
#Similar to 403 Forbidden, but specifically for use when authentication is
|
||||
#possible but has failed or not yet been provided. The response must include a
|
||||
#WWW-Authenticate header field containing a challenge applicable to the requested
|
||||
#resource. See Basic access authentication and Digest access authentication.
|
||||
|
||||
("402","Payment Required"),
|
||||
#Reserved for future use. The original intention was that this code might be
|
||||
#used as part of some form of digital cash or micropayment scheme, but that has
|
||||
#not happened, and this code is not usually used. As an example of its use,
|
||||
#however, Apple's MobileMe service generates a 402 error ("httpStatusCode:402" in
|
||||
#the Mac OS X Console log) if the MobileMe account is delinquent.
|
||||
|
||||
("403","Forbidden"),
|
||||
#The request was a legal request, but the server is refusing to respond to it.
|
||||
#Unlike a 401 Unauthorized response, authenticating will make no difference.
|
||||
|
||||
("404","Not Found"),
|
||||
#The requested resource could not be found but may be available again in the
|
||||
#future. Subsequent requests by the client are permissible.
|
||||
|
||||
("405","Method Not Allowed"),
|
||||
#A request was made of a resource using a request method not supported by that
|
||||
#resource; for example, using GET on a form which requires data to be
|
||||
#presented via POST, or using PUT on a read-only resource.
|
||||
|
||||
("406","Not Acceptable"),
|
||||
#The requested resource is only capable of generating content not acceptable
|
||||
#according to the Accept headers sent in the request.
|
||||
|
||||
("407","Proxy Authentication Required"),
|
||||
|
||||
("408","Request Timeout"),
|
||||
#The server timed out waiting for the request. According to W3 HTTP
|
||||
#specifications: "The client did not produce a request within the time that the
|
||||
#server was prepared to wait. The client MAY repeat the request without
|
||||
#modifications at any later time."
|
||||
|
||||
("409","Conflict"),
|
||||
#Indicates that the request could not be processed because of conflict in the
|
||||
#request, such as an edit conflict.
|
||||
|
||||
("410","Gone"),
|
||||
#Indicates that the resource requested is no longer available and will not be
|
||||
#available again. This should be used when a resource has been intentionally
|
||||
#removed and the resource should be purged. Upon receiving a 410 status code, the
|
||||
#client should not request the resource again in the future. Clients such as
|
||||
#search engines should remove the resource from their indices. Most use cases do
|
||||
#not require clients and search engines to purge the resource, and a "404 Not
|
||||
#Found" may be used instead.
|
||||
|
||||
("411","Length Required"),
|
||||
#The request did not specify the length of its content, which is required by the
|
||||
#requested resource.
|
||||
|
||||
("412","Precondition Failed"),
|
||||
#The server does not meet one of the preconditions that the requester put on the
|
||||
#request.
|
||||
|
||||
("413","Request Entity Too Large"),
|
||||
#The request is larger than the server is willing or able to process.
|
||||
|
||||
("414","Request-URI Too Long"),
|
||||
#The URI provided was too long for the server to process.
|
||||
|
||||
("415","Unsupported Media Type"),
|
||||
#The request entity has a media type which the server or resource does not
|
||||
#support. For example, the client uploads an image as image/svg+xml, but the
|
||||
#server requires that images use a different format.
|
||||
|
||||
("416","Requested Range Not Satisfiable"),
|
||||
#The client has asked for a portion of the file, but the server cannot supply
|
||||
#that portion. For example, if the client asked for a part of the file that
|
||||
#lies beyond the end of the file.
|
||||
|
||||
("417","Expectation Failed"),
|
||||
#The server cannot meet the requirements of the Expect request-header field.
|
||||
|
||||
("418","I'm a teapot"),
|
||||
#This code was defined in 1998 as one of the traditional IETF April Fools' jokes,
|
||||
#in RFC 2324, Hyper Text Coffee Pot Control Protocol, and is not expected to be
|
||||
#implemented by actual HTTP servers.
|
||||
|
||||
("422","Unprocessable Entity"),
|
||||
#The request was well-formed but was unable to be followed due to semantic
|
||||
#errors.
|
||||
|
||||
("423","Locked"),
|
||||
#The resource that is being accessed is locked.
|
||||
|
||||
("424","Failed Dependency"),
|
||||
#The request failed due to failure of a previous request (e.g. a PROPPATCH).
|
||||
|
||||
("425","Unordered Collection"),
|
||||
#Defined in drafts of "WebDAV Advanced Collections Protocol", but not present
|
||||
#in "Web Distributed Authoring and Versioning (WebDAV) Ordered Collections
|
||||
#Protocol".
|
||||
|
||||
("426","Upgrade Required"),
|
||||
#The client should switch to a different protocol such as TLS/1.0.
|
||||
|
||||
("444","No Response"),
|
||||
#A Nginx HTTP server extension. The server returns no information to the client
|
||||
#and closes the connection (useful as a deterrent for malware).
|
||||
|
||||
("449","Retry With"),
|
||||
#A Microsoft extension. The request should be retried after performing the
|
||||
#appropriate action.
|
||||
|
||||
("450","Blocked by Windows Parental Controls"),
|
||||
#A Microsoft extension. This error is given when Windows Parental Controls are
|
||||
#turned on and are blocking access to the given webpage.
|
||||
|
||||
("499","Client Closed Request"),
|
||||
#An Nginx HTTP server extension. This code is introduced to log the case when the
|
||||
#connection is closed by client while HTTP server is processing its request,
|
||||
#making server unable to send the HTTP header back.
|
||||
|
||||
#5xx Server Error
|
||||
#The server failed to fulfill an apparently valid request.
|
||||
#Response status codes beginning with the digit "5" indicate cases in which the
|
||||
#server is aware that it has encountered an error or is otherwise incapable of
|
||||
#performing the request. Except when responding to a HEAD request, the server
|
||||
#should include an entity containing an explanation of the error situation, and
|
||||
#indicate whether it is a temporary or permanent condition. Likewise, user agents
|
||||
#should display any included entity to the user. These response codes are
|
||||
#applicable to any request method.
|
||||
|
||||
("500","Internal Server Error"),
|
||||
#A generic error message, given when no more specific message is suitable.
|
||||
|
||||
("501","Not Implemented"),
|
||||
#The server either does not recognise the request method, or it lacks the ability
|
||||
#to fulfill the request.
|
||||
|
||||
("502","Bad Gateway"),
|
||||
#The server was acting as a gateway or proxy and received an invalid response
|
||||
#from the upstream server.
|
||||
|
||||
("503","Service Unavailable"),
|
||||
#The server is currently unavailable (because it is overloaded or down for
|
||||
#maintenance). Generally, this is a temporary state.
|
||||
|
||||
("504","Gateway Timeout"),
|
||||
#The server was acting as a gateway or proxy and did not receive a timely
|
||||
#response from the upstream server.
|
||||
|
||||
("505","HTTP Version Not Supported"),
|
||||
#The server does not support the HTTP protocol version used in the request.
|
||||
|
||||
("506","Variant Also Negotiates"),
|
||||
#Transparent content negotiation for the request results in a circular
|
||||
#reference.
|
||||
|
||||
("507","Insufficient Storage"),
|
||||
|
||||
("509","Bandwidth Limit Exceeded"),
|
||||
#This status code, while used by many servers, is not specified in any RFCs.
|
||||
|
||||
("510","Not Extended")
|
||||
#Further extensions to the request are required for the server to fulfill it.
|
||||
]
|
||||
end
|
|
@ -1,9 +1,4 @@
|
|||
|
||||
dummy = fun () -> log("Lastfm/audioscrobbler support was not compiled.")
|
||||
|
||||
%ifdef input.lastfm
|
||||
dummy = fun () -> ()
|
||||
|
||||
# Utility to compose last.fm URIs.
|
||||
# @category String
|
||||
# @param ~user Lastfm user
|
||||
|
@ -128,6 +123,3 @@ def lastfm.submit.full(
|
|||
end
|
||||
|
||||
%endif
|
||||
|
||||
dummy ()
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
#!/sbin/runscript
|
||||
|
||||
user=@install_user@
|
||||
group=@install_group@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
confdir=@sysconfdir@/liquidsoap
|
||||
liquidsoap=@bindir@/liquidsoap
|
||||
rundir=@localstatedir@/run/liquidsoap
|
||||
|
||||
depend() {
|
||||
after net icecast
|
||||
}
|
||||
|
||||
start() {
|
||||
cd $confdir
|
||||
for liq in *.liq ; do
|
||||
if test $liq != '*.liq' ; then
|
||||
ebegin "Starting $liq"
|
||||
start-stop-daemon --start --quiet --pidfile $rundir/${liq%.liq}.pid \
|
||||
--chuid $user:$group --exec $liquidsoap -- -d $confdir/$liq
|
||||
eend $?
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
stop() {
|
||||
cd $rundir
|
||||
for liq in *.pid ; do
|
||||
if test $liq != '*.pid' ; then
|
||||
ebegin "Stopping $liq"
|
||||
start-stop-daemon --stop --quiet --pidfile $liq
|
||||
eend $?
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
restart() {
|
||||
svc_stop
|
||||
einfo "Sleeping 4 seconds ..."
|
||||
sleep 4
|
||||
svc_start
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
#!/bin/sh
|
||||
### BEGIN INIT INFO
|
||||
# Provides: liquidsoap
|
||||
# Required-Start: $remote_fs $network $time
|
||||
# Required-Stop: $remote_fs $network $time
|
||||
# Should-Start:
|
||||
# Should-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Starts the liquidsoap daemon
|
||||
# Description:
|
||||
### END INIT INFO
|
||||
|
||||
user=@install_user@
|
||||
group=@install_group@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
confdir=@sysconfdir@/liquidsoap
|
||||
liquidsoap=@bindir@/liquidsoap
|
||||
rundir=@localstatedir@/run/liquidsoap
|
||||
|
||||
# Test if $rundir exists
|
||||
if [ ! -d $rundir ]; then
|
||||
mkdir -p $rundir;
|
||||
chown $user:$group $rundir
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
stop)
|
||||
echo -n "Stopping channels: "
|
||||
cd $rundir
|
||||
for liq in *.pid ; do
|
||||
if test $liq != '*.pid' ; then
|
||||
echo -n "$liq "
|
||||
start-stop-daemon --stop --quiet --pidfile $liq --retry 4
|
||||
fi
|
||||
done
|
||||
echo "OK"
|
||||
;;
|
||||
|
||||
start)
|
||||
echo -n "Starting channels: "
|
||||
cd $confdir
|
||||
for liq in *.liq ; do
|
||||
if test $liq != '*.liq' ; then
|
||||
echo -n "$liq "
|
||||
start-stop-daemon --start --quiet --pidfile $rundir/${liq%.liq}.pid \
|
||||
--chuid $user:$group --exec $liquidsoap -- -d $confdir/$liq
|
||||
fi
|
||||
done
|
||||
echo "OK"
|
||||
;;
|
||||
|
||||
restart|force-reload)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|force-reload}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
|
@ -1,15 +0,0 @@
|
|||
@localstatedir@/log/liquidsoap/*.log {
|
||||
compress
|
||||
rotate 5
|
||||
size 300k
|
||||
missingok
|
||||
notifempty
|
||||
sharedscripts
|
||||
postrotate
|
||||
for liq in @localstatedir@/run/liquidsoap/*.pid ; do
|
||||
if test $liq != '@localstatedir@/run/liquidsoap/*.pid' ; then
|
||||
start-stop-daemon --stop --signal USR1 --quiet --pidfile $liq
|
||||
fi
|
||||
done
|
||||
endscript
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script is called from liquidsoap for generating a file
|
||||
# for "say:voice/text" URIs.
|
||||
# Usage: liquidtts text output_file voice
|
||||
|
||||
echo $1 | @TEXT2WAVE@ -f 44100 > $2.tmp.wav && @SOX@ 2> /dev/null > /dev/null
|
||||
return=$?
|
||||
@RM@ $2.tmp.wav
|
||||
@NORMALIZE@ $2 2> /dev/null > /dev/null
|
||||
exit $return
|
|
@ -3,3 +3,5 @@
|
|||
%include "shoutcast.liq"
|
||||
%include "lastfm.liq"
|
||||
%include "flows.liq"
|
||||
%include "http.liq"
|
||||
%include "video_text.liq"
|
|
@ -4,14 +4,13 @@
|
|||
# @category Source / Output
|
||||
# @param ~id Output's ID
|
||||
# @param ~start Start output threads on operator initialization.
|
||||
# @param ~restart Restart output after a failure. By default, liquidsoap will stop if the output failed.
|
||||
# @param ~restart_delay Delay, in seconds, before attempting new connection, if restart is enabled.
|
||||
# @param ~user User for shout source connection. Useful only in special cases, like with per-mountpoint users.
|
||||
# @param ~icy_reset Reset shoutcast source buffer upon connecting (necessary for NSV).
|
||||
# @param ~dumpfile Dump stream to file, for debugging purpose. Disabled if empty.
|
||||
# @param ~fallible Allow the child source to fail, in which case the output will be (temporarily) stopped.
|
||||
# @param ~on_start Callback executed when outputting starts.
|
||||
# @param ~on_stop Callback executed when outputting stops.
|
||||
# @param ~on_error Callback executed when an error happens. If returned value is positive, connection wll be tried again after this amount of time (in seconds).
|
||||
# @param ~on_connect Callback executed when connection starts.
|
||||
# @param ~on_disconnect Callback executed when connection stops.
|
||||
# @param ~icy_metadata Send new metadata using the ICY protocol. One of: "guess", "true", "false"
|
||||
|
@ -20,7 +19,6 @@
|
|||
# @param s The source to output
|
||||
def output.shoutcast(
|
||||
~id="output.shoutcast",~start=true,
|
||||
~restart=false,~restart_delay=3,
|
||||
~host="localhost",~port=8000,
|
||||
~user="source",~password="hackme",
|
||||
~genre="Misc",~url="http://savonet.sf.net/",
|
||||
|
@ -29,7 +27,7 @@ def output.shoutcast(
|
|||
~on_connect={()}, ~on_disconnect={()},
|
||||
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||
~fallible=false,~on_start={()},~on_stop={()},
|
||||
e,s) =
|
||||
~on_error=fun(_)->3., e,s) =
|
||||
icy_reset = if icy_reset then "1" else "0" end
|
||||
headers = [("icy-aim",aim),("icy-irc",irc),
|
||||
("icy-icq",icq),("icy-reset",icy_reset)]
|
||||
|
@ -38,11 +36,10 @@ def output.shoutcast(
|
|||
id=id, headers=headers,
|
||||
start=start,icy_metadata=icy_metadata,
|
||||
on_connect=on_connect, on_disconnect=on_disconnect,
|
||||
restart=restart, restart_delay=restart_delay,
|
||||
host=host, port=port, user=user, password=password,
|
||||
genre=genre, url=url, description="UNUSED",
|
||||
public=public, dumpfile=dumpfile,encoding="ISO-8859-1",
|
||||
name=name, mount="/", protocol="icy",
|
||||
name=name, mount="/", protocol="icy",on_error=on_error,
|
||||
fallible=fallible,on_start=on_start,on_stop=on_stop,
|
||||
s)
|
||||
end
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
# This is the test for bug #403 from our old trac.
|
||||
#
|
||||
# Make a switch() declare itself ready and arrange to use it for the next
|
||||
# frame where it isn't ready anymore.
|
||||
#
|
||||
# Two switches A and B
|
||||
# A is only ready for a short period of time due to its predicates.
|
||||
# B reselects at the end of a frame just before A becomes unavailable
|
||||
# as a result, B has selected = A, attempts to stream it
|
||||
# but A finds itself not ready anymore.
|
||||
# In other words, B committed but A did not.
|
||||
|
||||
r = ref false
|
||||
pred = { v=!r ; r:=false ; v }
|
||||
add_timeout(2.,{ r := true ; (-1.) })
|
||||
|
||||
mixer = fallback(id="mixer", track_sensitive=false,
|
||||
[at(pred, sine(duration=3.)), blank()])
|
||||
|
||||
output.dummy(mixer)
|
||||
add_timeout(3.,{ print("TEST PASSED") ; shutdown() ; (-1.) })
|
|
@ -1,10 +0,0 @@
|
|||
# In LS-268 we realized that an incorrect assumption had
|
||||
# been made in code from LS-394, resulting in a crash in
|
||||
# case of source re-awakening.
|
||||
|
||||
p = input.http("http://localhost:8000/nonexistent")
|
||||
o = output.dummy(fallible=true,p)
|
||||
|
||||
add_timeout(2.,{ source.shutdown(o) ; (-1.) })
|
||||
add_timeout(3.,{ output.dummy(fallible=true,p) ; (-1.) })
|
||||
add_timeout(4.,{ shutdown() ; (-1.) })
|
|
@ -1,11 +0,0 @@
|
|||
s = on_track(
|
||||
fun(_)-> begin print("TEST PASSED") shutdown() end,
|
||||
blank(duration=1.))
|
||||
|
||||
r = ref false
|
||||
d = source.dynamic({ if !r then [s] else [] end })
|
||||
|
||||
output.dummy(mksafe(d))
|
||||
|
||||
add_timeout(2.,{r:=true;(-1.)})
|
||||
add_timeout(4.,{print("TEST FAILED");shutdown();(-1.)})
|
|
@ -1,15 +0,0 @@
|
|||
s1 = fail()
|
||||
s2 = on_track(
|
||||
fun(_)-> begin print("TEST PASSED") shutdown() end,
|
||||
blank(duration=1.))
|
||||
|
||||
r = ref 0
|
||||
d = source.dynamic({ if !r==1 then [s1]
|
||||
elsif !r==2 then [s2]
|
||||
else [] end })
|
||||
|
||||
output.dummy(mksafe(d))
|
||||
|
||||
add_timeout(2.,{r:=1;(-1.)})
|
||||
add_timeout(3.,{r:=2;(-1.)})
|
||||
add_timeout(5.,{print("TEST FAILED");shutdown();(-1.)})
|
|
@ -1,17 +0,0 @@
|
|||
# Scenario:
|
||||
# Let foo start using q, then stop it, skip in q.
|
||||
# When foo restarts it doesn't know that q isn't ready anymore,
|
||||
# which can lead to a crash.
|
||||
|
||||
q = once(sine(duration=10.))
|
||||
output.dummy(id="bar",mksafe(q))
|
||||
output.dummy(id="foo",fallback([amplify(1.,q),blank(duration=1.)]))
|
||||
|
||||
def at(t,s)
|
||||
add_timeout(t,{ignore(server.execute(s));(-1.)})
|
||||
end
|
||||
|
||||
at(3.,"foo.stop")
|
||||
at(4.,"bar.skip")
|
||||
at(5.,"foo.start")
|
||||
add_timeout(6.,{print("TEST PASSED");shutdown();(-1.)})
|
|
@ -1,13 +0,0 @@
|
|||
# In LS-503 we realized that a source may throw an
|
||||
# exception during output_get_ready call in the initial
|
||||
# main phase. This code reproduces the issue by throwing
|
||||
# an exception in output.icecast.
|
||||
|
||||
# Reopen stderr to /dev/null to
|
||||
# disable printing expected exception
|
||||
reopen.stderr("/dev/null")
|
||||
|
||||
p = input.http("http://localhost:8000/nonexistent")
|
||||
o = output.icecast(%wav,fallible=true,host="nonexistent",
|
||||
mount="test",p)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
DISTFILES = Makefile $(wildcard *.liq) $(wildcard *.pl)
|
||||
|
||||
top_srcdir = ../..
|
||||
include $(top_srcdir)/Makefile.rules
|
||||
|
||||
test:
|
||||
@for i in $(wildcard *.liq) ; do \
|
||||
echo -n "$$i... " ; $(top_srcdir)/src/liquidsoap -q - < ./$$i | head -n 1 ; \
|
||||
done
|
||||
@echo -n "type_errors.pl... " ; \
|
||||
if (./type_errors.pl > /dev/null 2> /dev/null) ; then \
|
||||
echo "TEST PASSED (check manually the prettiness of messages)" ; \
|
||||
else \
|
||||
echo "TEST FAILED" ; \
|
||||
fi
|
|
@ -1,43 +0,0 @@
|
|||
count = ref 1
|
||||
fail = ref false
|
||||
|
||||
def echo(s)
|
||||
# system("echo "^quote(s))
|
||||
if s != string_of(!count) then
|
||||
fail := true
|
||||
end
|
||||
count := !count + 1
|
||||
()
|
||||
end
|
||||
|
||||
def test(lbl,f)
|
||||
if f() then echo(lbl) else echo("fail "^lbl) end
|
||||
end
|
||||
|
||||
test("1",{ 1==1 })
|
||||
test("2",{ 1+1==2 })
|
||||
test("3",{ (-1)+2==1 })
|
||||
test("4",{ (-1)+2 <= 3*2 })
|
||||
test("5",{ true })
|
||||
test("6",{ true and true })
|
||||
test("7",{ 1==1 and 1==1 })
|
||||
test("8",{ (1==1) and (1==1) })
|
||||
test("9",{ true and (-1)+2 <= 3*2 })
|
||||
|
||||
l = [ ("bla",""), ("bli","x"), ("blo","xx"), ("blu","xxx"), ("dix","10") ]
|
||||
echo(l["dix"])
|
||||
test("11",{ 2 == list.length(string.split(separator="",l["blo"])) })
|
||||
|
||||
%ifdef foobarbaz
|
||||
if = if is not a well-formed expression, and we do not care...
|
||||
%endif
|
||||
|
||||
echo("1#{1+1}")
|
||||
echo(string_of(int_of_float(float_of_string(default=13.,"blah"))))
|
||||
|
||||
f=fun(x)->x
|
||||
# Checking that the following is not recursive:
|
||||
f=fun(x)->f(x)
|
||||
echo(string_of(f(14)))
|
||||
|
||||
if !fail then print("TEST FAILED") else print("TEST PASSED") end
|
|
@ -1,82 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict ;
|
||||
|
||||
my $liquidsoap = "../../src/liquidsoap";
|
||||
die unless -f $liquidsoap ;
|
||||
|
||||
$liquidsoap = "$liquidsoap -c";
|
||||
|
||||
sub section {
|
||||
print "\n*** $_[0] ***\n\n" ;
|
||||
}
|
||||
|
||||
sub incorrect {
|
||||
my $expr = pop ;
|
||||
print "Incorrect expression $expr...\n" ;
|
||||
system "$liquidsoap '$expr'" ;
|
||||
die unless (($?>>8)==1) ;
|
||||
print "\n" ;
|
||||
}
|
||||
|
||||
sub correct {
|
||||
my $expr = pop ;
|
||||
print "Correct expression $expr...\n" ;
|
||||
system "$liquidsoap -i '$expr'" ;
|
||||
die unless (($?>>8)==0) ;
|
||||
print "\n";
|
||||
}
|
||||
|
||||
section("BASIC");
|
||||
incorrect('[1]==["1"]');
|
||||
incorrect('1==["1"]');
|
||||
incorrect('1==(1,"1")');
|
||||
# In some of those examples the type error could be reported for a
|
||||
# sub-expression since we have location information.
|
||||
# With the concise error, it's still pretty good currently.
|
||||
incorrect('(1,1)==(1,"1")');
|
||||
incorrect('(1,1)==("1",1)');
|
||||
incorrect('1==request.create("")');
|
||||
incorrect('fun(x)->x(snd(x))');
|
||||
|
||||
section("SUBTYPING");
|
||||
incorrect('(1:unit)');
|
||||
correct('((blank():source(1,1,1)):source(*,*,*))');
|
||||
incorrect('((blank():source(*,*,*)):source(1,1,1))');
|
||||
# Next one requires the inference of a subtype (fixed vs. variable arity)
|
||||
correct('audio_to_stereo(add([]))');
|
||||
|
||||
section("CONSTRAINTS");
|
||||
incorrect('"bl"+"a"');
|
||||
incorrect('(fun(a,b)->a+b)==(fun(a,b)->a+b)');
|
||||
incorrect('fun(x)->x(x)'); # TODO is it an accident that we get same varname
|
||||
incorrect('def f(x) y=snd(x) y(x) end');
|
||||
|
||||
section("LET GENERALIZATION");
|
||||
correct('def f(x) = y=x ; y end f(3)+snd(f((1,2)))');
|
||||
incorrect('def f(x) = y=x ; y end f(3)+"3"');
|
||||
|
||||
section("ARGUMENTS");
|
||||
# The errors should be about the type of the param, not of the function.
|
||||
incorrect('1+"1"');
|
||||
# Also, a special simple error is expected for obvious labelling mistakes.
|
||||
incorrect('fallback(transitions=[],xxxxxxxxxxx=[])');
|
||||
incorrect('fallback(transitions=[],transitions=[])');
|
||||
|
||||
section("FUNCTIONS");
|
||||
incorrect('fallback(transitions=[fun(~l)->1])');
|
||||
incorrect('fallback(transitions=[fun(~l=1)->1])');
|
||||
incorrect('fallback(transitions=[fun(x,y=blank())->y])');
|
||||
incorrect('fallback(transitions=[fun(x,y)->0])');
|
||||
correct('f=fallback(transitions=[fun(x,y,a=2)->x])');
|
||||
incorrect('fallback(transitions=[fun(x,y)->y+1])');
|
||||
correct('x=fun(f)->f(3) y=x(fun(f,u="1")->u)');
|
||||
|
||||
section("CONTENT KIND");
|
||||
incorrect('output.file(%vorbis(stereo),"foo",mean(blank()))');
|
||||
incorrect('output.file(%vorbis(stereo),"foo",video.add_image(blank()))');
|
||||
incorrect('def f(x) = output.file(%vorbis(stereo),"",x) output.file(%vorbis(mono),"",x) end');
|
||||
incorrect('add([output.file(%vorbis(stereo),"",blank()),output.file(%vorbis(mono),"",blank())])');
|
||||
incorrect('add([mean(blank()),audio_to_stereo(add([]))])');
|
||||
|
||||
print "Everything's good!\n" ;
|
|
@ -1,112 +0,0 @@
|
|||
# Check these examples with: liquidsoap --no-libs -i -c typing.liq
|
||||
|
||||
# TODO Throughout this file, parsing locations displayed in error messages
|
||||
# are often much too inaccurate.
|
||||
|
||||
# Check that some polymorphism is allowed.
|
||||
# id : (string,'a)->'a
|
||||
def id(a,b)
|
||||
log(a)
|
||||
b
|
||||
end
|
||||
ignore("bla"==id("bla","bla"))
|
||||
ignore(0==id("zero",0))
|
||||
|
||||
# Reporting locations for the next error is non-trivial, because it is about
|
||||
# an instantiation of the type of id. The deep error doesn't have relevant
|
||||
# information about why the int should be a string, the outer one has.
|
||||
# id(0,0)
|
||||
|
||||
# Polymorphism is limited to outer generalizations, this is not system F.
|
||||
# apply : ((string)->'a)->'a
|
||||
def apply(f)
|
||||
f("bla")
|
||||
# f is not polymorphic, the following is forbidden:
|
||||
# f(0)
|
||||
# f(f)
|
||||
end
|
||||
|
||||
# The level checks forbid abusive generalization.
|
||||
# id' : ('a)->'a
|
||||
def id'(x)
|
||||
# If one isn't careful about levels/scoping, f2 gets the type ('a)->'b
|
||||
# and so does twisted_id.
|
||||
def f2(y)
|
||||
x
|
||||
end
|
||||
f2(x)
|
||||
end
|
||||
|
||||
# More errors...
|
||||
# 0=="0"
|
||||
# [3,""]
|
||||
|
||||
# Subtyping, functions and lists.
|
||||
f1 = fun () -> 3
|
||||
f2 = fun (a=1) -> a
|
||||
|
||||
# This is OK, l1 is a list of elements of type f1.
|
||||
l1 = [f1,f2]
|
||||
list.iter(fun (f) -> log(string_of(f())), l1)
|
||||
# Forbidden. Indeed, f1 doesn't accept any argument -- although f2 does.
|
||||
# Here the error message may even be too detailed since it goes back to the
|
||||
# definition of l1 and requires that f1 has type (int)->int.
|
||||
# list.iter(fun (f) -> log(string_of(f(42))), l1)
|
||||
|
||||
# Actually, this is forbidden too, but the reason is more complex...
|
||||
# The infered type for the function is ((int)->int)->unit,
|
||||
# and (int)->int is not a subtype of (?int)->int.
|
||||
# There's no most general answer here since (?int)->int is not a
|
||||
# subtype of (int)->int either.
|
||||
# list.iter(fun (f) -> log(string_of(f(42))), [f2])
|
||||
|
||||
# Unlike l1, this is not OK, since we don't leave open subtyping constraints
|
||||
# while infering types.
|
||||
# I hope we can make the inference smarter in the future, without obfuscating
|
||||
# the error messages too much.
|
||||
# The type error here shows the use of all the displayed positions:
|
||||
# f1 has type t1, f2 has type t2, t1 should be <: t2
|
||||
# l2 = [ f2, f1 ]
|
||||
|
||||
# An error where contravariance flips the roles of both sides..
|
||||
# [fun (x) -> x+1, fun (y) -> y^"."]
|
||||
|
||||
# An error without much locations..
|
||||
# TODO An explaination about the missing label would help a lot here.
|
||||
# def f(f)
|
||||
# f(output.icecast.vorbis)
|
||||
# f(output.icecast.mp3)
|
||||
# end
|
||||
|
||||
# This causes an occur-check error.
|
||||
# TODO The printing of the types breaks the sharing of one EVAR
|
||||
# across two types. Here the sharing is actually the origin of the occur-check
|
||||
# error. And it's not easy to understand..
|
||||
# omega = fun (x) -> x(x)
|
||||
|
||||
# Now let's test ad-hoc polymorphism.
|
||||
|
||||
echo = fun(x) -> system("echo #{quote(string_of(x))}")
|
||||
|
||||
ignore("bla")
|
||||
ignore((1,3.12))
|
||||
ignore(1 + 1)
|
||||
ignore(1. + 2.14)
|
||||
|
||||
# string is not a Num
|
||||
# echo("bl"+"a")
|
||||
|
||||
ignore(1 <= 2)
|
||||
ignore((1,2) == (1,3))
|
||||
|
||||
# float <> int
|
||||
# echo(1 == 2.)
|
||||
|
||||
# source is not an Ord
|
||||
# echo(blank()==blank())
|
||||
|
||||
def sum_eq(a,b)
|
||||
a+b == a
|
||||
end
|
||||
|
||||
print("TEST PASSED")
|
|
@ -1,61 +0,0 @@
|
|||
# run this file through "liquidsoap -c -i"
|
||||
# to see if pretty printing looks pretty enough
|
||||
# for more checks, pass --twidth 78
|
||||
|
||||
x = (blank() : source(2,3,4))
|
||||
pair = (x,x)
|
||||
x = (x,x)
|
||||
x = (x,x)
|
||||
x = (x,x)
|
||||
|
||||
def output.shoutcast(
|
||||
~id="output.shoutcast",~start=true,
|
||||
~restart=false,~restart_delay=3,
|
||||
~host="localhost",~port=8000,
|
||||
~user="source",~password="hackme",
|
||||
~genre="Misc",~url="http://savonet.sf.net/",
|
||||
~name="OCaml Radio!",~public=true, ~format="",
|
||||
~dumpfile="", ~icy_metadata="guess",
|
||||
~on_connect={()}, ~on_disconnect={()},
|
||||
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||
~fallible=false,~on_start={()},~on_stop={()},
|
||||
e,s)
|
||||
=
|
||||
42
|
||||
end
|
||||
|
||||
x = (output.shoutcast,pair)
|
||||
|
||||
def output.shoutcast(
|
||||
~id="output.shoutcast",~start=true,
|
||||
~restart=false,~restart_delay=3,
|
||||
~host="localhost",~port=8000,
|
||||
~user="source",~password="hackme",
|
||||
~genre="Misc",~url="http://savonet.sf.net/",
|
||||
~name="OCaml Radio!",~public=true, ~format="",
|
||||
~dumpfile="", ~icy_metadata="guess",
|
||||
~on_connect={()}, ~on_disconnect={()},
|
||||
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||
~fallible=false,~on_start={()},~on_stop={()},
|
||||
e,s)
|
||||
=
|
||||
(pair,42)
|
||||
end
|
||||
|
||||
def output.shoutcast(
|
||||
~id="output.shoutcast",~start=true,
|
||||
~restart=false,~restart_delay=3,
|
||||
~host="localhost",~port=8000,
|
||||
~user="source",~password="hackme",
|
||||
~genre="Misc",~url="http://savonet.sf.net/",
|
||||
~name="OCaml Radio!",~public=true, ~format="",
|
||||
~dumpfile="", ~icy_metadata="guess",
|
||||
~on_connect={()}, ~on_disconnect={()},
|
||||
~aim="",~icq="",~irc="",~icy_reset=true,
|
||||
~fallible=false,~on_start={()},~on_stop={()},
|
||||
e,s)
|
||||
=
|
||||
(blank() : source(3,0,0))
|
||||
end
|
||||
|
||||
x = (output.shoutcast,blank())
|
|
@ -257,7 +257,7 @@ def test_process(command)
|
|||
end
|
||||
|
||||
# Split an url of the form foo?arg=bar&arg2=bar2
|
||||
# into ("foo",[("arg","bar"),("arg2","bar2")]
|
||||
# into ("foo",[("arg","bar"),("arg2","bar2")]).
|
||||
# @category String
|
||||
# @param uri Url to split
|
||||
def url.split(uri) =
|
||||
|
@ -278,11 +278,11 @@ def url.split(uri) =
|
|||
end
|
||||
|
||||
# Register a server/telnet command to
|
||||
# update a source's metadata. Returns
|
||||
# update a source's metadata. Returns
|
||||
# a new source, which will receive the
|
||||
# updated metadata. Semantics is the
|
||||
# same as pre 1.0 insert_metadata operator,
|
||||
# i.e. @insert key1="val1",key2="val2",..@
|
||||
# updated metadata. It behaves just like
|
||||
# the pre-1.0 insert_metadata() operator,
|
||||
# i.e. insert key1="val1",key2="val2",...
|
||||
# @category Source / Track Processing
|
||||
# @param ~id Force the value of the source ID.
|
||||
def server.insert_metadata(~id="",s) =
|
||||
|
@ -384,9 +384,17 @@ def read(~hide=false)
|
|||
s
|
||||
end
|
||||
|
||||
file.mime_default = fun (_) -> ""
|
||||
# Dummy implementation of file.mime
|
||||
# @category System
|
||||
def file.mime_default(_)
|
||||
""
|
||||
end
|
||||
%ifdef file.mime
|
||||
file.mime_default = file.mime
|
||||
# Alias of file.mime (because it is available)
|
||||
# @category System
|
||||
def file.mime_default(file)
|
||||
file.mime(file)
|
||||
end
|
||||
%endif
|
||||
|
||||
# Generic mime test. First try to use file.mime if it exist.
|
||||
|
@ -678,9 +686,9 @@ end
|
|||
add_protocol("replay_gain", replaygain_protocol)
|
||||
|
||||
# Enable replay gain metadata resolver. This resolver will
|
||||
# process any file decoded by liquidsoap and add a @replay_gain@
|
||||
# process any file decoded by liquidsoap and add a replay_gain
|
||||
# metadata when this value could be computed. For a finer-grained
|
||||
# replay gain processing, use the @replay_gain@ protocol.
|
||||
# replay gain processing, use the replay_gain protocol.
|
||||
# @category Liquidsoap
|
||||
# @param ~extract_replaygain The extraction program
|
||||
def enable_replaygain_metadata(
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
%ifdef video.add_text.gd
|
||||
# Add a scrolling line of text on video frames.
|
||||
# @param ~id Force the value of the source ID.
|
||||
# @param ~color Text color (in 0xRRGGBB format).
|
||||
# @param ~cycle Cycle text.
|
||||
# @param ~font Path to ttf font file.
|
||||
# @param ~metadata Change text on a particular metadata \
|
||||
# (empty string means disabled).
|
||||
# @param ~size Font size.
|
||||
# @param ~speed Speed in pixels per second (0 means no scrolling).
|
||||
# @param ~x x offset (negative means from right).
|
||||
# @param ~y y offset (negative means from bottom).
|
||||
# @param text Text to display.
|
||||
def video.add_text(~id="",~color=16777215,~cycle=true,
|
||||
~font=configure.default_font,
|
||||
~metadata="",~size=18,~speed=70,~x=-1,~y=-5,
|
||||
text,source)
|
||||
video.add_text.gd(id=id,color=color,cycle=cycle,font=font,metadata=metadata,
|
||||
size=size,speed=speed,x=x,y=y,text,source)
|
||||
end
|
||||
%endif
|
||||
|
||||
%ifdef video.add_text.sdl
|
||||
# Add a scrolling line of text on video frames.
|
||||
# @param ~id Force the value of the source ID.
|
||||
# @param ~color Text color (in 0xRRGGBB format).
|
||||
# @param ~cycle Cycle text.
|
||||
# @param ~font Path to ttf font file.
|
||||
# @param ~metadata Change text on a particular metadata \
|
||||
# (empty string means disabled).
|
||||
# @param ~size Font size.
|
||||
# @param ~speed Speed in pixels per second (0 means no scrolling).
|
||||
# @param ~x x offset (negative means from right).
|
||||
# @param ~y y offset (negative means from bottom).
|
||||
# @param text Text to display.
|
||||
def video.add_text(~id="",~color=16777215,~cycle=true,
|
||||
~font=configure.default_font,
|
||||
~metadata="",~size=18,~speed=70,~x=-1,~y=-5,
|
||||
text,source)
|
||||
video.add_text.sdl(id=id,color=color,cycle=cycle,font=font,metadata=metadata,
|
||||
size=size,speed=speed,x=x,y=y,text,source)
|
||||
end
|
||||
%endif
|
|
@ -49,8 +49,6 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
|
|||
password = pass,
|
||||
mount = mount_point,
|
||||
fallible = true,
|
||||
restart = true,
|
||||
restart_delay = 5,
|
||||
url = url,
|
||||
description = description,
|
||||
genre = genre,
|
||||
|
@ -132,8 +130,6 @@ def output_to(output_type, type, bitrate, host, port, pass, mount_point, url, de
|
|||
port = port,
|
||||
password = pass,
|
||||
fallible = true,
|
||||
restart = true,
|
||||
restart_delay = 5,
|
||||
url = !url_ref,
|
||||
genre = !genre_ref,
|
||||
name = !description_ref,
|
||||
|
|
|
@ -51,7 +51,7 @@ add_skip_command(s)
|
|||
s = map_metadata(append_title, s)
|
||||
|
||||
if output_sound_device then
|
||||
ignore(output.alsa(s))
|
||||
ignore(out(s))
|
||||
end
|
||||
|
||||
if s1_output != "disabled" then
|
||||
|
|
|
@ -258,7 +258,8 @@ class CommandListener(Thread):
|
|||
|
||||
#remove show from shows to record.
|
||||
del self.shows_to_record[start_time]
|
||||
self.time_till_next_show = 3600
|
||||
time_till_next_show = self.get_time_till_next_show()
|
||||
self.time_till_next_show = time_till_next_show
|
||||
except Exception,e :
|
||||
self.logger.error(e)
|
||||
else:
|
||||
|
@ -297,6 +298,7 @@ class CommandListener(Thread):
|
|||
# start recording
|
||||
self.start_record()
|
||||
except Exception, e:
|
||||
self.logger.info(e)
|
||||
time.sleep(3)
|
||||
|
||||
loops += 1
|
||||
|
|
Loading…
Reference in New Issue