diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php
index cd6f64da6..f07281da3 100644
--- a/airtime_mvc/application/controllers/ApiController.php
+++ b/airtime_mvc/application/controllers/ApiController.php
@@ -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);
}
}
diff --git a/airtime_mvc/application/controllers/DashboardController.php b/airtime_mvc/application/controllers/DashboardController.php
index f51597ad9..8b918137d 100644
--- a/airtime_mvc/application/controllers/DashboardController.php
+++ b/airtime_mvc/application/controllers/DashboardController.php
@@ -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()
diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php
index c69014689..28cc0e382 100644
--- a/airtime_mvc/application/controllers/LibraryController.php
+++ b/airtime_mvc/application/controllers/LibraryController.php
@@ -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');
}
}
diff --git a/airtime_mvc/application/models/MusicDir.php b/airtime_mvc/application/models/MusicDir.php
index 3b26c6da9..8010b4c0f 100644
--- a/airtime_mvc/application/models/MusicDir.php
+++ b/airtime_mvc/application/models/MusicDir.php
@@ -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;
diff --git a/airtime_mvc/application/models/Component.php b/airtime_mvc/application/models/ServiceRegister.php
similarity index 94%
rename from airtime_mvc/application/models/Component.php
rename to airtime_mvc/application/models/ServiceRegister.php
index 2771f79eb..47c647829 100644
--- a/airtime_mvc/application/models/Component.php
+++ b/airtime_mvc/application/models/ServiceRegister.php
@@ -1,5 +1,5 @@
});
-
+ 
-
\ No newline at end of file
+
diff --git a/airtime_mvc/application/views/scripts/form/support-setting.phtml b/airtime_mvc/application/views/scripts/form/support-setting.phtml
index 9eb9af547..9794f8159 100644
--- a/airtime_mvc/application/views/scripts/form/support-setting.phtml
+++ b/airtime_mvc/application/views/scripts/form/support-setting.phtml
@@ -134,7 +134,7 @@
element->getView()->logoImg){?>
-
+
element->getElement('Logo') ?>
@@ -175,4 +175,4 @@
Terms and Conditions
-
\ No newline at end of file
+
diff --git a/airtime_mvc/public/js/airtime/dashboard/helperfunctions.js b/airtime_mvc/public/js/airtime/dashboard/helperfunctions.js
index e1abb3f2d..510c43fee 100644
--- a/airtime_mvc/public/js/airtime/dashboard/helperfunctions.js
+++ b/airtime_mvc/public/js/airtime/dashboard/helperfunctions.js
@@ -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");
+ }
+}
diff --git a/airtime_mvc/public/js/airtime/nowplaying/register.js b/airtime_mvc/public/js/airtime/nowplaying/register.js
index 084e933d0..fe1e3b38f 100644
--- a/airtime_mvc/public/js/airtime/nowplaying/register.js
+++ b/airtime_mvc/public/js/airtime/nowplaying/register.js
@@ -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" );
- }
-}
\ No newline at end of file
+ img.css("width", newWidth);
+ }else if( width == height && width > targetWidth){
+ img.css("height", targetHeight+"px");
+ img.css("width", targetWidth+"px" );
+ }
+}
diff --git a/airtime_mvc/public/js/airtime/preferences/support-setting.js b/airtime_mvc/public/js/airtime/preferences/support-setting.js
index acd3fe671..d26c39cf8 100644
--- a/airtime_mvc/public/js/airtime/preferences/support-setting.js
+++ b/airtime_mvc/public/js/airtime/preferences/support-setting.js
@@ -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");
diff --git a/airtime_mvc/public/js/jplayer/skin/jplayer.blue.monday.css b/airtime_mvc/public/js/jplayer/skin/jplayer.blue.monday.css
index 3c880aa63..1ef4fc2fe 100644
--- a/airtime_mvc/public/js/jplayer/skin/jplayer.blue.monday.css
+++ b/airtime_mvc/public/js/jplayer/skin/jplayer.blue.monday.css
@@ -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;
diff --git a/install_minimal/include/airtime-install.php b/install_minimal/include/airtime-install.php
index 683e95293..8f66d61f2 100644
--- a/install_minimal/include/airtime-install.php
+++ b/install_minimal/include/airtime-install.php
@@ -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');
diff --git a/install_minimal/upgrades/airtime-1.9.0/airtime-upgrade.php b/install_minimal/upgrades/airtime-1.9.0/airtime-upgrade.php
index ebcb9358a..38a7e8688 100644
--- a/install_minimal/upgrades/airtime-1.9.0/airtime-upgrade.php
+++ b/install_minimal/upgrades/airtime-1.9.0/airtime-upgrade.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();
diff --git a/install_minimal/upgrades/upgrade-template/UpgradeCommon.php b/install_minimal/upgrades/upgrade-template/UpgradeCommon.php
index 57ee794cd..c106ee4b0 100644
--- a/install_minimal/upgrades/upgrade-template/UpgradeCommon.php
+++ b/install_minimal/upgrades/upgrade-template/UpgradeCommon.php
@@ -70,7 +70,7 @@ class UpgradeCommon{
}
}
- $default_suffix = "200";
+ $default_suffix = CONF_BACKUP_SUFFIX;
self::CreateIniFiles($default_suffix);
self::MergeConfigFiles($configFiles, $suffix);
}
diff --git a/install_minimal/upgrades/upgrade-template/airtime-upgrade.php b/install_minimal/upgrades/upgrade-template/airtime-upgrade.php
index 42aa0c287..5812e84ac 100644
--- a/install_minimal/upgrades/upgrade-template/airtime-upgrade.php
+++ b/install_minimal/upgrades/upgrade-template/airtime-upgrade.php
@@ -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(){
}
diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py
index c98f4433e..2d6df7fa8 100755
--- a/python_apps/api_clients/api_client.py
+++ b/python_apps/api_clients/api_client.py
@@ -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
diff --git a/python_apps/pypo/liquidsoap_bin/liquidsoap-natty-amd64 b/python_apps/pypo/liquidsoap_bin/liquidsoap-natty-amd64
index 4e1067210..a54073750 100755
Binary files a/python_apps/pypo/liquidsoap_bin/liquidsoap-natty-amd64 and b/python_apps/pypo/liquidsoap_bin/liquidsoap-natty-amd64 differ
diff --git a/python_apps/pypo/liquidsoap_scripts/library/Makefile b/python_apps/pypo/liquidsoap_scripts/library/Makefile
deleted file mode 100644
index d10777180..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/Makefile
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.pl b/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.pl
deleted file mode 100755
index a2f10206e..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.pl
+++ /dev/null
@@ -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 \n" unless @ARGV ;
-$telnet->print($ARGV[0]) ;
-my ($output,$end) = $telnet->waitfor('/END$/') ;
-print $output;
diff --git a/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.rb b/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.rb
deleted file mode 100755
index 2dc65e6f8..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/ask-liquidsoap.rb
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/externals.liq b/python_apps/pypo/liquidsoap_scripts/library/externals.liq
index 78f48197f..a3b1a2bc3 100644
--- a/python_apps/pypo/liquidsoap_scripts/library/externals.liq
+++ b/python_apps/pypo/liquidsoap_scripts/library/externals.liq
@@ -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) =
diff --git a/python_apps/pypo/liquidsoap_scripts/library/extract-replaygain b/python_apps/pypo/liquidsoap_scripts/library/extract-replaygain
deleted file mode 100755
index 20afbc179..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/extract-replaygain
+++ /dev/null
@@ -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";
-
-}
diff --git a/python_apps/pypo/liquidsoap_scripts/library/http.liq b/python_apps/pypo/liquidsoap_scripts/library/http.liq
new file mode 100644
index 000000000..109baf41e
--- /dev/null
+++ b/python_apps/pypo/liquidsoap_scripts/library/http.liq
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/http_codes.liq b/python_apps/pypo/liquidsoap_scripts/library/http_codes.liq
new file mode 100644
index 000000000..a2359a18e
--- /dev/null
+++ b/python_apps/pypo/liquidsoap_scripts/library/http_codes.liq
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/lastfm.liq b/python_apps/pypo/liquidsoap_scripts/library/lastfm.liq
index 0886bf0a2..7b52c5b14 100644
--- a/python_apps/pypo/liquidsoap_scripts/library/lastfm.liq
+++ b/python_apps/pypo/liquidsoap_scripts/library/lastfm.liq
@@ -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 ()
-
diff --git a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.gentoo.initd.in b/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.gentoo.initd.in
deleted file mode 100755
index 3281fe925..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.gentoo.initd.in
+++ /dev/null
@@ -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
-}
diff --git a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.initd.in b/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.initd.in
deleted file mode 100755
index 9b447a159..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.initd.in
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.logrotate.in b/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.logrotate.in
deleted file mode 100644
index 9b154ae45..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/liquidsoap.logrotate.in
+++ /dev/null
@@ -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
-}
diff --git a/python_apps/pypo/liquidsoap_scripts/library/liquidtts.in b/python_apps/pypo/liquidsoap_scripts/library/liquidtts.in
deleted file mode 100644
index c7e2f906f..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/liquidtts.in
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/pervasives.liq b/python_apps/pypo/liquidsoap_scripts/library/pervasives.liq
index 93ad95202..bd894766b 100644
--- a/python_apps/pypo/liquidsoap_scripts/library/pervasives.liq
+++ b/python_apps/pypo/liquidsoap_scripts/library/pervasives.liq
@@ -3,3 +3,5 @@
%include "shoutcast.liq"
%include "lastfm.liq"
%include "flows.liq"
+%include "http.liq"
+%include "video_text.liq"
\ No newline at end of file
diff --git a/python_apps/pypo/liquidsoap_scripts/library/shoutcast.liq b/python_apps/pypo/liquidsoap_scripts/library/shoutcast.liq
index e7dc167c9..1cdc2fbd9 100644
--- a/python_apps/pypo/liquidsoap_scripts/library/shoutcast.liq
+++ b/python_apps/pypo/liquidsoap_scripts/library/shoutcast.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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/BUG403.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/BUG403.liq
deleted file mode 100644
index c86eaac08..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/BUG403.liq
+++ /dev/null
@@ -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.) })
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/LS268.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/LS268.liq
deleted file mode 100644
index 195a1d9a2..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/LS268.liq
+++ /dev/null
@@ -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.) })
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-1.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-1.liq
deleted file mode 100644
index 2e30612a4..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-1.liq
+++ /dev/null
@@ -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.)})
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-2.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-2.liq
deleted file mode 100644
index ff9ca3817..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/LS354-2.liq
+++ /dev/null
@@ -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.)})
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/LS460.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/LS460.liq
deleted file mode 100644
index 5c7e530f8..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/LS460.liq
+++ /dev/null
@@ -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.)})
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/LS503.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/LS503.liq
deleted file mode 100644
index 49dadf1a4..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/LS503.liq
+++ /dev/null
@@ -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)
-
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/Makefile b/python_apps/pypo/liquidsoap_scripts/library/tests/Makefile
deleted file mode 100644
index e9cda96a8..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/Makefile
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/eval.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/eval.liq
deleted file mode 100644
index 6a930daff..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/eval.liq
+++ /dev/null
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/type_errors.pl b/python_apps/pypo/liquidsoap_scripts/library/tests/type_errors.pl
deleted file mode 100755
index f832eaed7..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/type_errors.pl
+++ /dev/null
@@ -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" ;
diff --git a/python_apps/pypo/liquidsoap_scripts/library/tests/typing.liq b/python_apps/pypo/liquidsoap_scripts/library/tests/typing.liq
deleted file mode 100644
index 8162ebaed..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/tests/typing.liq
+++ /dev/null
@@ -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")
diff --git a/python_apps/pypo/liquidsoap_scripts/library/type_printing.liq b/python_apps/pypo/liquidsoap_scripts/library/type_printing.liq
deleted file mode 100644
index 805734b6d..000000000
--- a/python_apps/pypo/liquidsoap_scripts/library/type_printing.liq
+++ /dev/null
@@ -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())
diff --git a/python_apps/pypo/liquidsoap_scripts/library/utils.liq b/python_apps/pypo/liquidsoap_scripts/library/utils.liq
index a28e9c8d8..5967662f4 100644
--- a/python_apps/pypo/liquidsoap_scripts/library/utils.liq
+++ b/python_apps/pypo/liquidsoap_scripts/library/utils.liq
@@ -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(
diff --git a/python_apps/pypo/liquidsoap_scripts/library/video_text.liq b/python_apps/pypo/liquidsoap_scripts/library/video_text.liq
new file mode 100644
index 000000000..b372a1f7b
--- /dev/null
+++ b/python_apps/pypo/liquidsoap_scripts/library/video_text.liq
@@ -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
diff --git a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq
index 1c2f0dafd..c59a211f0 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq
@@ -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,
diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
index d4c4f08ed..1ea328c86 100644
--- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq
+++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq
@@ -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
diff --git a/python_apps/show-recorder/recorder.py b/python_apps/show-recorder/recorder.py
index a53f9cdd1..fc6a41d5c 100644
--- a/python_apps/show-recorder/recorder.py
+++ b/python_apps/show-recorder/recorder.py
@@ -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