parent
0b82107d28
commit
3259eb06a0
|
@ -8,7 +8,7 @@ set("server.telnet.port", 1234)
|
||||||
|
|
||||||
time = ref string_of(gettimeofday())
|
time = ref string_of(gettimeofday())
|
||||||
|
|
||||||
queue = audio_to_stereo(request.queue(id="queue", length=0.5))
|
queue = audio_to_stereo(request.equeue(id="queue", length=0.5))
|
||||||
queue = cue_cut(queue)
|
queue = cue_cut(queue)
|
||||||
|
|
||||||
pypo_data = ref '0'
|
pypo_data = ref '0'
|
||||||
|
|
|
@ -9,10 +9,16 @@ import telnetlib
|
||||||
import calendar
|
import calendar
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
"""
|
||||||
|
It is possible to use a list as a queue, where the first element added is the first element
|
||||||
|
retrieved ("first-in, first-out"); however, lists are not efficient for this purpose. Let's use
|
||||||
|
"deque"
|
||||||
|
"""
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
from api_clients import api_client
|
from api_clients import api_client
|
||||||
|
|
||||||
from configobj import ConfigObj
|
from configobj import ConfigObj
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +31,7 @@ try:
|
||||||
LS_HOST = config['ls_host']
|
LS_HOST = config['ls_host']
|
||||||
LS_PORT = config['ls_port']
|
LS_PORT = config['ls_port']
|
||||||
PUSH_INTERVAL = 2
|
PUSH_INTERVAL = 2
|
||||||
|
MAX_LIQUIDSOAP_QUEUE_LENGTH = 2
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.error('Error loading config file %s', e)
|
logger.error('Error loading config file %s', e)
|
||||||
|
@ -42,6 +49,8 @@ class PypoPush(Thread):
|
||||||
self.push_ahead = 10
|
self.push_ahead = 10
|
||||||
self.last_end_time = 0
|
self.last_end_time = 0
|
||||||
|
|
||||||
|
self.liquidsoap_queue = deque()
|
||||||
|
|
||||||
self.logger = logging.getLogger('push')
|
self.logger = logging.getLogger('push')
|
||||||
|
|
||||||
def push(self):
|
def push(self):
|
||||||
|
@ -52,44 +61,54 @@ class PypoPush(Thread):
|
||||||
then liquidsoap is asked (via telnet) to reload and immediately play it.
|
then liquidsoap is asked (via telnet) to reload and immediately play it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.update_liquidsoap_queue()
|
||||||
|
|
||||||
timenow = time.time()
|
timenow = time.time()
|
||||||
# get a new schedule from pypo-fetch
|
# get a new schedule from pypo-fetch
|
||||||
if not self.queue.empty():
|
if not self.queue.empty():
|
||||||
# make sure we get the latest schedule
|
# make sure we get the latest schedule
|
||||||
while not self.queue.empty():
|
while not self.queue.empty():
|
||||||
self.media = self.queue.get()
|
self.media = self.queue.get()
|
||||||
|
|
||||||
self.logger.debug("Received data from pypo-fetch")
|
self.logger.debug("Received data from pypo-fetch")
|
||||||
self.logger.debug('media %s' % json.dumps(self.media))
|
self.logger.debug('media %s' % json.dumps(self.media))
|
||||||
|
self.handle_new_media(self.media)
|
||||||
|
|
||||||
|
|
||||||
media = self.media
|
media = self.media
|
||||||
|
|
||||||
currently_on_air = False
|
if len(self.liquidsoap_queue) < MAX_LIQUIDSOAP_QUEUE_LENGTH:
|
||||||
if media:
|
"""
|
||||||
tnow = time.gmtime(timenow)
|
We only care about what's scheduled if the number of items in the queue is less
|
||||||
tcoming = time.gmtime(timenow + self.push_ahead)
|
than our max queue limit.
|
||||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
"""
|
||||||
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
|
currently_on_air = False
|
||||||
|
if media:
|
||||||
|
tnow = time.gmtime(timenow)
|
||||||
|
tcoming = time.gmtime(timenow + self.push_ahead)
|
||||||
|
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||||
|
str_tcoming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcoming[0], tcoming[1], tcoming[2], tcoming[3], tcoming[4], tcoming[5])
|
||||||
|
|
||||||
for key in media.keys():
|
for key in media.keys():
|
||||||
media_item = media[key]
|
media_item = media[key]
|
||||||
item_start = media_item['start'][0:19]
|
item_start = media_item['start'][0:19]
|
||||||
|
|
||||||
if str_tnow_s <= item_start and item_start < str_tcoming_s:
|
|
||||||
"""
|
|
||||||
If the media item starts in the next 30 seconds, push it to the queue.
|
|
||||||
"""
|
|
||||||
self.logger.debug('Preparing to push media item scheduled at: %s', key)
|
|
||||||
|
|
||||||
if self.push_to_liquidsoap(media_item):
|
|
||||||
self.logger.debug("Pushed to liquidsoap, updating 'played' status.")
|
|
||||||
|
|
||||||
|
if str_tnow_s <= item_start and item_start < str_tcoming_s:
|
||||||
"""
|
"""
|
||||||
Temporary solution to make sure we don't push the same track multiple times.
|
If the media item starts in the next 30 seconds, push it to the queue.
|
||||||
"""
|
"""
|
||||||
del media[key]
|
self.logger.debug('Preparing to push media item scheduled at: %s', key)
|
||||||
|
|
||||||
currently_on_air = True
|
if self.push_to_liquidsoap(media_item):
|
||||||
self.liquidsoap_state_play = True
|
self.logger.debug("Pushed to liquidsoap, updating 'played' status.")
|
||||||
|
|
||||||
|
"""
|
||||||
|
Temporary solution to make sure we don't push the same track multiple times.
|
||||||
|
"""
|
||||||
|
del media[key]
|
||||||
|
|
||||||
|
currently_on_air = True
|
||||||
|
self.liquidsoap_state_play = True
|
||||||
|
|
||||||
def push_to_liquidsoap(self, media_item):
|
def push_to_liquidsoap(self, media_item):
|
||||||
"""
|
"""
|
||||||
|
@ -123,6 +142,60 @@ class PypoPush(Thread):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def update_liquidsoap_queue(self):
|
||||||
|
"""
|
||||||
|
the queue variable liquidsoap_queue is our attempt to mirror
|
||||||
|
what liquidsoap actually has in its own queue. Liquidsoap automatically
|
||||||
|
updates its own queue when an item finishes playing, we have to do this
|
||||||
|
manually.
|
||||||
|
|
||||||
|
This function will iterate through the liquidsoap_queue and remove items
|
||||||
|
whose end time are in the past.
|
||||||
|
"""
|
||||||
|
|
||||||
|
tnow = time.gmtime(timenow)
|
||||||
|
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||||
|
|
||||||
|
while len(self.liquidsoap_queue) > 0:
|
||||||
|
if self.liquidsoap_queue[0]["end"] < str_tnow_s:
|
||||||
|
self.liquidsoap_queue.popleft()
|
||||||
|
|
||||||
|
def handle_new_media(self, media):
|
||||||
|
"""
|
||||||
|
This function's purpose is to gracefully handle situations where
|
||||||
|
Liquidsoap already has a track in its queue, but the schedule
|
||||||
|
has changed.
|
||||||
|
|
||||||
|
If the media_item is already being played, then we can't
|
||||||
|
do anything about it. If it is in the Liquidsoap queue, but not
|
||||||
|
yet playing then we can remove it. Note that currently
|
||||||
|
there can only ever be one media_item in the queue that isn't
|
||||||
|
being played (for a max of two items in the queue).
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO: What happens if we remove the second item in the queue when
|
||||||
|
it just became the primary item?
|
||||||
|
"""
|
||||||
|
if len(self.liquidsoap_queue) > 1:
|
||||||
|
media_item = self.liquidsoap_queue[1]
|
||||||
|
|
||||||
|
if media["id"] != liquidsoap_queue["id"]:
|
||||||
|
"""
|
||||||
|
The md5s are the not same, so a different
|
||||||
|
item has been scheduled!
|
||||||
|
"""
|
||||||
|
#remove from actual liquidsoap queue
|
||||||
|
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||||
|
msg = 'queue.remove %s\n' % media_item["queue_id"]
|
||||||
|
tn.write(msg)
|
||||||
|
tn.write("exit\n")
|
||||||
|
self.logger.debug(tn.read_all())
|
||||||
|
|
||||||
|
#remove from our liquidsoap queue
|
||||||
|
self.liquidsoap_queue.remove(media_item)
|
||||||
|
|
||||||
|
|
||||||
def sleep_until_start(self, media_item):
|
def sleep_until_start(self, media_item):
|
||||||
"""
|
"""
|
||||||
The purpose of this function is to look at the difference between
|
The purpose of this function is to look at the difference between
|
||||||
|
@ -162,8 +235,14 @@ class PypoPush(Thread):
|
||||||
|
|
||||||
annotation = media_item['annotation']
|
annotation = media_item['annotation']
|
||||||
msg = 'queue.push %s\n' % annotation.encode('utf-8')
|
msg = 'queue.push %s\n' % annotation.encode('utf-8')
|
||||||
tn.write(msg)
|
|
||||||
self.logger.debug(msg)
|
self.logger.debug(msg)
|
||||||
|
tn.write(msg)
|
||||||
|
queue_id = tn.read_until("\r\n").strip("\r\n")
|
||||||
|
|
||||||
|
media_item['queue_id'] = queue_id
|
||||||
|
|
||||||
|
#add media_item to the end of our queue
|
||||||
|
self.liquidsoap_queue.append(media_item)
|
||||||
|
|
||||||
show_name = media_item['show_name']
|
show_name = media_item['show_name']
|
||||||
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
msg = 'vars.show_name %s\n' % show_name.encode('utf-8')
|
||||||
|
|
Loading…
Reference in New Issue