Merge branch '2.1.x' of dev.sourcefabric.org:airtime into 2.1.x

This commit is contained in:
denise 2012-07-03 18:23:04 -04:00
commit 6d056daa2f
11 changed files with 59 additions and 34 deletions

View File

@ -1,3 +1,10 @@
=======
CREDITS
=======
Version 2.1.3
-------------
Same as previous version.
======= =======
CREDITS CREDITS
======= =======

View File

@ -1,2 +1,2 @@
PRODUCT_ID=Airtime PRODUCT_ID=Airtime
PRODUCT_RELEASE=2.1.2 PRODUCT_RELEASE=2.1.3

View File

@ -1,3 +1,15 @@
2.1.3 - July 4th, 2012
* Changes
* Clarify inputs and output labels under stream settings
* Bug Fixes
* Fix playout engine crashing in rare cases after the system is restarted
* Fix entries in the Calendar unable to have multiple icons (recorded icon, soundcloud icon etc.)
* Fixed unwatching a watched folder with a large number of files (50,000+) can take a long time
* Fixed files deleted in the Web UI would delete files from the disk in watched folders
* Fixed jQuery widgets not showing the incorrectly showing the past Sunday on Sunday
* Fixed dragging and dropping tracks into a live show could cause to web UI to become unsynchronized from what is actually playing
* Fixed unable to receive mono streams for Master or Show source rebroadcasts
2.1.2 - June 18th, 2012 2.1.2 - June 18th, 2012
* Bug Fixes * Bug Fixes
* Fixed problem where playout engine may not retrieve program schedule after extended periods of user inactivity. * Fixed problem where playout engine may not retrieve program schedule after extended periods of user inactivity.

View File

@ -152,10 +152,6 @@ fi
if [ -e /etc/init.d/airtime-playout ]; then if [ -e /etc/init.d/airtime-playout ]; then
invoke-rc.d airtime-playout stop > /dev/null 2>&1 invoke-rc.d airtime-playout stop > /dev/null 2>&1
fi fi
if [ -e /etc/init.d/airtime-show-recorder ]; then
invoke-rc.d airtime-show-recorder stop > /dev/null 2>&1
fi
#export these variables to make them available in sub bash scripts #export these variables to make them available in sub bash scripts
export DO_UPGRADE export DO_UPGRADE

View File

@ -1,3 +1,3 @@
<?php <?php
define('AIRTIME_VERSION', '2.1.2'); define('AIRTIME_VERSION', '2.1.3');

View File

@ -111,6 +111,10 @@ if (strcmp($version, "2.1.1") < 0){
if (strcmp($version, "2.1.2") < 0){ if (strcmp($version, "2.1.2") < 0){
passthru("php --php-ini $SCRIPTPATH/../airtime-php.ini $SCRIPTPATH/../upgrades/airtime-2.1.2/airtime-upgrade.php"); passthru("php --php-ini $SCRIPTPATH/../airtime-php.ini $SCRIPTPATH/../upgrades/airtime-2.1.2/airtime-upgrade.php");
pause(); pause();
} }
if (strcmp($version, "2.1.3") < 0){
passthru("php --php-ini $SCRIPTPATH/../airtime-php.ini $SCRIPTPATH/../upgrades/airtime-2.1.3/airtime-upgrade.php");
pause();
}
echo "******************************* Upgrade Complete *******************************".PHP_EOL; echo "******************************* Upgrade Complete *******************************".PHP_EOL;

View File

@ -20,7 +20,7 @@ from configobj import ConfigObj
import string import string
import hashlib import hashlib
AIRTIME_VERSION = "2.1.2" AIRTIME_VERSION = "2.1.3"
def api_client_factory(config, logger=None): def api_client_factory(config, logger=None):
if logger != None: if logger != None:

View File

@ -31,7 +31,7 @@ class MediaMonitorCommon:
def is_temp_file(self, filename): def is_temp_file(self, filename):
info = filename.split(".") info = filename.split(".")
# if file doesn't have any extension, info[-2] throws exception # if file doesn't have any extension, info[-2] throws exception
# Hence, checking length of info before we do anything # Hence, checking length of info before we do anything
if(len(info) >= 2): if(len(info) >= 2):
@ -56,7 +56,7 @@ class MediaMonitorCommon:
try: try:
uid = pwd.getpwnam(euid)[2] uid = pwd.getpwnam(euid)[2]
gid = grp.getgrnam(egid)[2] gid = grp.getgrnam(egid)[2]
#drop root permissions and become "nobody" #drop root permissions and become "nobody"
os.setegid(gid) os.setegid(gid)
os.seteuid(uid) os.seteuid(uid)
@ -85,15 +85,15 @@ class MediaMonitorCommon:
except Exception, e: except Exception, e:
self.logger.warn(u"Failed to check owner/group/permissions for %s", item) self.logger.warn(u"Failed to check owner/group/permissions for %s", item)
return False return False
def make_file_readable(self, pathname, is_dir): def make_file_readable(self, pathname, is_dir):
if is_dir: if is_dir:
#set to 755 #set to 755
os.chmod(pathname, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR | stat.S_IRGRP|stat.S_IXGRP | stat.S_IROTH|stat.S_IXOTH) os.chmod(pathname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
else: else:
#set to 644 #set to 644
os.chmod(pathname, stat.S_IRUSR|stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) os.chmod(pathname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
def make_readable(self, pathname): def make_readable(self, pathname):
""" """
Should only call this function if is_readable() returns False. This function Should only call this function if is_readable() returns False. This function
@ -120,7 +120,7 @@ class MediaMonitorCommon:
except Exception, e: except Exception, e:
#something went wrong while we were trying to make world readable. #something went wrong while we were trying to make world readable.
return False return False
return True return True
#checks if path is a directory, and if it doesnt exist, then creates it. #checks if path is a directory, and if it doesnt exist, then creates it.
@ -165,7 +165,7 @@ class MediaMonitorCommon:
#non-critical exception because we probably tried to delete a non-empty dir. #non-critical exception because we probably tried to delete a non-empty dir.
#Don't need to log this, let's just "return" #Don't need to log this, let's just "return"
pass pass
#checks if path exists already in stor. If the path exists and the md5s are the #checks if path exists already in stor. If the path exists and the md5s are the
@ -195,7 +195,7 @@ class MediaMonitorCommon:
self.logger.error("Trying %s", new_filepath) self.logger.error("Trying %s", new_filepath)
if(os.path.exists(new_filepath)): if(os.path.exists(new_filepath)):
i = i+1; i = i + 1;
else: else:
filepath = new_filepath filepath = new_filepath
break break
@ -231,7 +231,7 @@ class MediaMonitorCommon:
md['MDATA_KEY_TRACKNUMBER'] = "%02d" % (int(md['MDATA_KEY_TRACKNUMBER'])) md['MDATA_KEY_TRACKNUMBER'] = "%02d" % (int(md['MDATA_KEY_TRACKNUMBER']))
#format bitrate as 128kbps #format bitrate as 128kbps
md['MDATA_KEY_BITRATE'] = str(md['MDATA_KEY_BITRATE']/1000)+"kbps" md['MDATA_KEY_BITRATE'] = str(md['MDATA_KEY_BITRATE'] / 1000) + "kbps"
filepath = None filepath = None
#file is recorded by Airtime #file is recorded by Airtime
@ -274,7 +274,7 @@ class MediaMonitorCommon:
if p.returncode != 0: if p.returncode != 0:
self.logger.warn("command \n%s\n return with a non-zero return value", command) self.logger.warn("command \n%s\n return with a non-zero return value", command)
self.logger.error(stderr) self.logger.error(stderr)
try: try:
""" """
File name charset encoding is UTF-8. File name charset encoding is UTF-8.
@ -283,14 +283,14 @@ class MediaMonitorCommon:
except Exception, e: except Exception, e:
stdout = None stdout = None
self.logger.error("Could not decode %s using UTF-8" % stdout) self.logger.error("Could not decode %s using UTF-8" % stdout)
return stdout return stdout
def scan_dir_for_new_files(self, dir): def scan_dir_for_new_files(self, dir):
command = 'find "%s" -iname "*.ogg" -o -iname "*.mp3" -type f -readable' % dir.replace('"', '\\"') command = 'find "%s" -iname "*.ogg" -o -iname "*.mp3" -type f -readable' % dir.replace('"', '\\"')
self.logger.debug(command) self.logger.debug(command)
stdout = self.exec_command(command) stdout = self.exec_command(command)
return stdout.splitlines() return stdout.splitlines()
def touch_index_file(self): def touch_index_file(self):
@ -312,7 +312,7 @@ class MediaMonitorCommon:
self.move_file(pathname, filepath) self.move_file(pathname, filepath)
self.make_readable(filepath) self.make_readable(filepath)
return filepath return filepath
def test_file_playability(self, pathname): def test_file_playability(self, pathname):
#when there is an single apostrophe inside of a string quoted by apostrophes, we can only escape it by replace that apostrophe #when there is an single apostrophe inside of a string quoted by apostrophes, we can only escape it by replace that apostrophe
#with '\''. This breaks the string into two, and inserts an escaped single quote in between them. #with '\''. This breaks the string into two, and inserts an escaped single quote in between them.
@ -323,13 +323,13 @@ class MediaMonitorCommon:
if return_code != 0: if return_code != 0:
#print pathname for py-interpreter.log #print pathname for py-interpreter.log
print pathname print pathname
return (return_code == 0) return (return_code == 0)
def move_to_problem_dir(self, source): def move_to_problem_dir(self, source):
dest = os.path.join(self.config.problem_directory, os.path.basename(source)) dest = os.path.join(self.config.problem_directory, os.path.basename(source))
try: try:
omask = os.umask(0) omask = os.umask(0)
os.rename(source, dest) os.rename(source, dest)
@ -338,4 +338,4 @@ class MediaMonitorCommon:
self.logger.error("traceback: %s", traceback.format_exc()) self.logger.error("traceback: %s", traceback.format_exc())
finally: finally:
os.umask(omask) os.umask(omask)

View File

@ -429,7 +429,7 @@ class PypoFetch(Thread):
fileExt = os.path.splitext(media_item['uri'])[1] fileExt = os.path.splitext(media_item['uri'])[1]
dst = os.path.join(download_dir, media_item['id'] + fileExt) dst = os.path.join(download_dir, media_item['id'] + fileExt)
media_item['dst'] = dst media_item['dst'] = dst
media_item['started_copying'] = False media_item['file_ready'] = False
media_filtered[key] = media_item media_filtered[key] = media_item
self.media_prepare_queue.put(copy.copy(media_filtered)) self.media_prepare_queue.put(copy.copy(media_filtered))

View File

@ -60,22 +60,28 @@ class PypoFile(Thread):
except Exception, e: except Exception, e:
dst_exists = False dst_exists = False
media_item['already_exist'] = False
do_copy = False do_copy = False
if dst_exists: if dst_exists:
if src_size != dst_size: if src_size != dst_size:
do_copy = True do_copy = True
else: else:
self.logger.debug("file %s already exists in local cache as %s, skipping cpoying..." % (src, dst)) self.logger.debug("file %s already exists in local cache as %s, skipping copying..." % (src, dst))
media_item['already_exist'] = True
else: else:
do_copy = True do_copy = True
media_item['file_ready'] = not do_copy
if do_copy: if do_copy:
self.logger.debug("copying from %s to local cache %s" % (src, dst)) self.logger.debug("copying from %s to local cache %s" % (src, dst))
try: try:
media_item['started_copying'] = True """
List file as "ready" before it starts copying because by the time
Liquidsoap is ready to play this file, it should have at least started
copying (and can continue copying while Liquidsoap reads from the beginning
of the file)
"""
media_item['file_ready'] = True
""" """
copy will overwrite dst if it already exists copy will overwrite dst if it already exists

View File

@ -340,11 +340,11 @@ class PypoPush(Thread):
give up on it. give up on it.
""" """
iter_num = 0 iter_num = 0
while not media_item['started_copying'] and iter_num < 50: while not media_item['file_ready'] and iter_num < 50:
time.sleep(0.1) time.sleep(0.1)
iter_num += 1 iter_num += 1
if media_item['started_copying'] or media_item['already_exist']: if media_item['file_ready']:
self.telnet_to_liquidsoap(media_item) self.telnet_to_liquidsoap(media_item)
else: else:
self.logger.warn("File %s did not become ready in less than 5 seconds. Skipping...", media_item['dst']) self.logger.warn("File %s did not become ready in less than 5 seconds. Skipping...", media_item['dst'])