Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

Conflicts:
	python_apps/media-monitor/airtimefilemonitor/airtimeprocessevent.py
This commit is contained in:
James 2011-10-04 17:22:19 -04:00
commit 2786d40db8
52 changed files with 533 additions and 796 deletions

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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');
}
}

View File

@ -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;

View File

@ -1,5 +1,5 @@
<?php
class Application_Model_Component {
class Application_Model_ServiceRegister {
public static function Register($p_componentName, $p_ipAddress){

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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>

View File

@ -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>

View File

@ -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");
}
}

View File

@ -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" );
}
}

View File

@ -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");

View File

@ -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;

View File

@ -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');

View File

@ -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();

View File

@ -70,7 +70,7 @@ class UpgradeCommon{
}
}
$default_suffix = "200";
$default_suffix = CONF_BACKUP_SUFFIX;
self::CreateIniFiles($default_suffix);
self::MergeConfigFiles($configFiles, $suffix);
}

View File

@ -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(){
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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) =

View File

@ -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";
}

View File

@ -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

View File

@ -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

View File

@ -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 ()

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -3,3 +3,5 @@
%include "shoutcast.liq"
%include "lastfm.liq"
%include "flows.liq"
%include "http.liq"
%include "video_text.liq"

View File

@ -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

View File

@ -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.) })

View File

@ -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.) })

View File

@ -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.)})

View File

@ -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.)})

View File

@ -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.)})

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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" ;

View File

@ -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")

View File

@ -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())

View File

@ -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(

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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