Pypo fixes and improvements
General: * Moved pypo author info into one file * Added two database columns in schedule table: "schedule_group_played" and "media_item_played". API clients: * Created get_liquidsoap_data() function which allows you to give arbitrary data to liquidsoap. * Added documentation * Renamed functions to make it more obvious what is happening pypo_cli: * Got rid of more constants that were not needed * Created function set_export_source() to reduce code repetition * Separated the downloading of the schedule from tracking what has been played. The tracking info is now kept in a separate file. This fixes the major bug that the playlist keeps restarting for the first minute of playback. * converted more print statements to debug statements pypoTester: * Now uses samples from the audio_samples directory, and schedules two audio clips back-to-back.
This commit is contained in:
parent
a138424451
commit
3613812012
|
@ -1,6 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###############################################################################
|
||||
# This file holds the implementations for all the API clients.
|
||||
#
|
||||
# If you want to develop a new client, here are some suggestions:
|
||||
# Get the fetch methods working first, then the push, then the liquidsoap notifier.
|
||||
# You will probably want to create a script on your server side to automatically
|
||||
# schedule a playlist one minute from the current time.
|
||||
###############################################################################
|
||||
|
||||
import sys
|
||||
import time
|
||||
import urllib
|
||||
|
@ -22,49 +31,82 @@ def api_client_factory(config):
|
|||
|
||||
class ApiClientInterface:
|
||||
|
||||
# This is optional.
|
||||
# Implementation: optional
|
||||
#
|
||||
# Called from: beginning of all scripts
|
||||
#
|
||||
# Should exit the program if this version of pypo is not compatible with
|
||||
# 3rd party software.
|
||||
def check_version(self):
|
||||
nil
|
||||
pass
|
||||
|
||||
# Required.
|
||||
# Implementation: Required
|
||||
#
|
||||
# Called from: fetch loop
|
||||
#
|
||||
# This is the main method you need to implement when creating a new API client.
|
||||
# start and end are for testing purposes.
|
||||
# start and end are strings in the format YYYY-DD-MM-hh-mm-ss
|
||||
def get_schedule(self, start=None, end=None):
|
||||
return 0, []
|
||||
|
||||
# Required.
|
||||
# Implementation: Required
|
||||
#
|
||||
# Called from: fetch loop
|
||||
#
|
||||
# This downloads the media from the server.
|
||||
def get_media(self, src, dst):
|
||||
nil
|
||||
pass
|
||||
|
||||
# This is optional.
|
||||
# You dont actually have to implement this function for the liquidsoap playout to work.
|
||||
def update_scheduled_item(self, item_id, value):
|
||||
nil
|
||||
# Implementation: optional
|
||||
#
|
||||
# Called from: push loop
|
||||
#
|
||||
# Tell server that the scheduled *playlist* has started.
|
||||
def notify_scheduled_item_start_playing(self, pkey, schedule):
|
||||
pass
|
||||
|
||||
# This is optional.
|
||||
# Implementation: optional
|
||||
# You dont actually have to implement this function for the liquidsoap playout to work.
|
||||
def update_start_playing(self, playlist_type, export_source, media_id, playlist_id, transmission_id):
|
||||
nil
|
||||
#
|
||||
# Called from: pypo_notify.py
|
||||
#
|
||||
# This is a callback from liquidsoap, we use this to notify about the
|
||||
# currently playing *song*. We get passed a JSON string which we handed to
|
||||
# liquidsoap in get_liquidsoap_data().
|
||||
def notify_media_item_start_playing(self, data, media_id):
|
||||
pass
|
||||
|
||||
# Implementation: optional
|
||||
# You dont actually have to implement this function for the liquidsoap playout to work.
|
||||
def generate_range_dp(self):
|
||||
nil
|
||||
pass
|
||||
|
||||
# Implementation: optional
|
||||
#
|
||||
# Called from: push loop
|
||||
#
|
||||
# Return a dict of extra info you want to pass to liquidsoap
|
||||
# You will be able to use this data in update_start_playing
|
||||
def get_liquidsoap_data(self, pkey, schedule):
|
||||
pass
|
||||
|
||||
# Put here whatever tests you want to run to make sure your API is working
|
||||
def test(self):
|
||||
nil
|
||||
pass
|
||||
|
||||
|
||||
#def get_media_type(self, playlist):
|
||||
# nil
|
||||
|
||||
################################################################################
|
||||
# Campcaster API Client
|
||||
################################################################################
|
||||
|
||||
class CampcasterApiClient(ApiClientInterface):
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
#self.api_auth = api_auth
|
||||
|
||||
def __get_campcaster_version(self):
|
||||
logger = logging.getLogger()
|
||||
|
@ -109,7 +151,6 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
def test(self):
|
||||
logger = logging.getLogger()
|
||||
status, items = self.get_schedule('2010-01-01-00-00-00', '2011-01-01-00-00-00')
|
||||
#print items
|
||||
schedule = items["playlists"]
|
||||
logger.debug("Number of playlists found: %s", str(len(schedule)))
|
||||
count = 1
|
||||
|
@ -117,12 +158,10 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
logger.debug("Playlist #%s",str(count))
|
||||
count+=1
|
||||
#logger.info("found playlist at %s", pkey)
|
||||
#print pkey
|
||||
playlist = schedule[pkey]
|
||||
for item in playlist["medias"]:
|
||||
filename = urlparse(item["uri"])
|
||||
filename = filename.query[5:]
|
||||
#print filename
|
||||
self.get_media(item["uri"], filename)
|
||||
|
||||
|
||||
|
@ -142,6 +181,7 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
print 'pypo is compatible with this version of Campcaster.'
|
||||
print
|
||||
|
||||
|
||||
def get_schedule(self, start=None, end=None):
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
@ -183,26 +223,26 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
except Exception, e:
|
||||
print e
|
||||
|
||||
schedule = response["playlists"]
|
||||
scheduleKeys = sorted(schedule.iterkeys())
|
||||
|
||||
# Remove all playlists that have passed current time
|
||||
try:
|
||||
tnow = time.localtime(time.time())
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
toRemove = []
|
||||
for pkey in scheduleKeys:
|
||||
if (str_tnow_s > schedule[pkey]['end']):
|
||||
toRemove.append(pkey)
|
||||
else:
|
||||
break
|
||||
#logger.debug("Remove keys: %s", toRemove)
|
||||
for index in toRemove:
|
||||
del schedule[index]
|
||||
#logger.debug("Schedule dict: %s", schedule)
|
||||
except Exception, e:
|
||||
logger.debug("'Ignore Past Playlists' feature not supported by API: %s", e)
|
||||
response["playlists"] = schedule
|
||||
#schedule = response["playlists"]
|
||||
#scheduleKeys = sorted(schedule.iterkeys())
|
||||
#
|
||||
## Remove all playlists that have passed current time
|
||||
#try:
|
||||
# tnow = time.localtime(time.time())
|
||||
# str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
# toRemove = []
|
||||
# for pkey in scheduleKeys:
|
||||
# if (str_tnow_s > schedule[pkey]['end']):
|
||||
# toRemove.append(pkey)
|
||||
# else:
|
||||
# break
|
||||
# #logger.debug("Remove keys: %s", toRemove)
|
||||
# for index in toRemove:
|
||||
# del schedule[index]
|
||||
# #logger.debug("Schedule dict: %s", schedule)
|
||||
#except Exception, e:
|
||||
# logger.debug("'Ignore Past Playlists' feature not supported by API: %s", e)
|
||||
#response["playlists"] = schedule
|
||||
|
||||
return status, response
|
||||
|
||||
|
@ -220,51 +260,58 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
logger.error("%s", e)
|
||||
|
||||
|
||||
def update_scheduled_item(self, item_id, value):
|
||||
pass
|
||||
#logger = logging.getLogger()
|
||||
#
|
||||
#url = self.config["base_url"] + self.config["api_base"] + self.config["update_item_url"]
|
||||
#
|
||||
#try:
|
||||
# response = urllib.urlopen(url, self.api_auth)
|
||||
# response = json.read(response.read())
|
||||
# logger.info("API-Status %s", response['status'])
|
||||
# logger.info("API-Message %s", response['message'])
|
||||
#
|
||||
#except Exception, e:
|
||||
# print e
|
||||
# api_status = False
|
||||
# logger.critical("Unable to connect - %s", e)
|
||||
#
|
||||
#return response
|
||||
"""
|
||||
Tell server that the scheduled *playlist* has started.
|
||||
"""
|
||||
def notify_scheduled_item_start_playing(self, pkey, schedule):
|
||||
logger = logging.getLogger()
|
||||
playlist = schedule[pkey]
|
||||
schedule_id = playlist["schedule_id"]
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["update_item_url"]
|
||||
url = url.replace("%%schedule_id%%", str(schedule_id))
|
||||
url += "&api_key=" + self.config["api_key"]
|
||||
logger.debug(url)
|
||||
|
||||
try:
|
||||
response = urllib.urlopen(url)
|
||||
response = json.read(response.read())
|
||||
logger.info("API-Status %s", response['status'])
|
||||
logger.info("API-Message %s", response['message'])
|
||||
|
||||
except Exception, e:
|
||||
logger.critical("Unable to connect - %s", e)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def update_start_playing(self, playlist_type, export_source, media_id, playlist_id, transmission_id):
|
||||
pass
|
||||
#logger = logging.getLogger()
|
||||
#
|
||||
#url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
|
||||
#url = url.replace("%%playlist_type%%", str(playlist_type))
|
||||
#url = url.replace("%%export_source%%", str(export_source))
|
||||
#url = url.replace("%%media_id%%", str(media_id))
|
||||
#url = url.replace("%%playlist_id%%", str(playlist_id))
|
||||
#url = url.replace("%%transmission_id%%", str(transmission_id))
|
||||
#print url
|
||||
#
|
||||
#try:
|
||||
# response = urllib.urlopen(url)
|
||||
# response = json.read(response.read())
|
||||
# logger.info("API-Status %s", response['status'])
|
||||
# logger.info("API-Message %s", response['message'])
|
||||
# logger.info("TXT %s", response['str_dls'])
|
||||
#
|
||||
#except Exception, e:
|
||||
# print e
|
||||
# api_status = False
|
||||
# logger.critical("Unable to connect - %s", e)
|
||||
#
|
||||
#return response
|
||||
|
||||
"""
|
||||
This is a callback from liquidsoap, we use this to notify about the
|
||||
currently playing *song*. We get passed a JSON string which we handed to
|
||||
liquidsoap in get_liquidsoap_data().
|
||||
"""
|
||||
def notify_media_item_start_playing(self, data, media_id):
|
||||
logger = logging.getLogger()
|
||||
response = ''
|
||||
if (data[0] != '{'):
|
||||
return response
|
||||
try:
|
||||
data = json.read(data)
|
||||
logger.debug(str(data))
|
||||
schedule_id = data["schedule_id"]
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
|
||||
url = url.replace("%%media_id%%", str(media_id))
|
||||
url = url.replace("%%schedule_id%%", str(schedule_id))
|
||||
url += "&api_key=" + self.config["api_key"]
|
||||
logger.debug(url)
|
||||
response = urllib.urlopen(url)
|
||||
response = json.read(response.read())
|
||||
logger.info("API-Status %s", response['status'])
|
||||
logger.info("API-Message %s", response['message'])
|
||||
|
||||
except Exception, e:
|
||||
logger.critical("Exception: %s", e)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def generate_range_dp(self):
|
||||
|
@ -287,6 +334,17 @@ class CampcasterApiClient(ApiClientInterface):
|
|||
#
|
||||
#return response
|
||||
|
||||
def get_liquidsoap_data(self, pkey, schedule):
|
||||
logger = logging.getLogger()
|
||||
playlist = schedule[pkey]
|
||||
data = dict()
|
||||
try:
|
||||
data["schedule_id"] = playlist['id']
|
||||
except Exception, e:
|
||||
data["schedule_id"] = 0
|
||||
data = json.write(data)
|
||||
return data
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
|
@ -327,7 +385,7 @@ class ObpApiClient():
|
|||
|
||||
|
||||
def get_obp_version(self):
|
||||
logger = logging.getLogger("ObpApiClient.get_obp_version")
|
||||
logger = logging.getLogger()
|
||||
|
||||
# lookup OBP version
|
||||
url = self.config["base_url"] + self.config["api_base"]+ self.config["version_url"]
|
||||
|
@ -369,7 +427,7 @@ class ObpApiClient():
|
|||
|
||||
|
||||
def get_schedule(self, start=None, end=None):
|
||||
logger = logging.getLogger("CampcasterApiClient.get_schedule")
|
||||
logger = logging.getLogger()
|
||||
|
||||
"""
|
||||
calculate start/end time range (format: YYYY-DD-MM-hh-mm-ss,YYYY-DD-MM-hh-mm-ss)
|
||||
|
@ -421,13 +479,15 @@ class ObpApiClient():
|
|||
logger.error("%s", e)
|
||||
|
||||
|
||||
def update_scheduled_item(self, item_id, value):
|
||||
logger = logging.getLogger("ObpApiClient.update_scheduled_item")
|
||||
# lookup OBP version
|
||||
|
||||
"""
|
||||
Tell server that the scheduled *playlist* has started.
|
||||
"""
|
||||
def notify_scheduled_item_start_playing(self, pkey, schedule):
|
||||
#def update_scheduled_item(self, item_id, value):
|
||||
logger = logging.getLogger()
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["update_item_url"]
|
||||
url = url.replace("%%item_id%%", str(item_id))
|
||||
url = url.replace("%%played%%", str(value))
|
||||
url = url.replace("%%item_id%%", str(schedule[pkey]["id"]))
|
||||
url = url.replace("%%played%%", "1")
|
||||
|
||||
try:
|
||||
response = urllib.urlopen(url, self.api_auth)
|
||||
|
@ -442,9 +502,18 @@ class ObpApiClient():
|
|||
|
||||
return response
|
||||
|
||||
|
||||
def update_start_playing(self, playlist_type, export_source, media_id, playlist_id, transmission_id):
|
||||
logger = logging.getLogger("ApiClient.update_scheduled_item")
|
||||
"""
|
||||
This is a callback from liquidsoap, we use this to notify about the
|
||||
currently playing *song*. We get passed a JSON string which we handed to
|
||||
liquidsoap in get_liquidsoap_data().
|
||||
"""
|
||||
def notify_media_item_start_playing(self, data, media_id):
|
||||
# def update_start_playing(self, playlist_type, export_source, media_id, playlist_id, transmission_id):
|
||||
logger = logging.getLogger()
|
||||
playlist_type = data["playlist_type"]
|
||||
export_source = data["export_source"]
|
||||
playlist_id = data["playlist_id"]
|
||||
transmission_id = data["transmission_id"]
|
||||
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
|
||||
url = url.replace("%%playlist_type%%", str(playlist_type))
|
||||
|
@ -470,7 +539,7 @@ class ObpApiClient():
|
|||
|
||||
|
||||
def generate_range_dp(self):
|
||||
logger = logging.getLogger("ObpApiClient.generate_range_dp")
|
||||
logger = logging.getLogger()
|
||||
|
||||
url = self.config["base_url"] + self.config["api_base"] + self.config["generate_range_url"]
|
||||
|
||||
|
@ -486,5 +555,20 @@ class ObpApiClient():
|
|||
api_status = False
|
||||
logger.critical("Unable to handle the OBP API request - %s", e)
|
||||
|
||||
|
||||
return response
|
||||
|
||||
def get_liquidsoap_data(self, pkey, schedule):
|
||||
playlist = schedule[pkey]
|
||||
data = dict()
|
||||
data["ptype"] = playlist['subtype']
|
||||
try:
|
||||
data["user_id"] = playlist['user_id']
|
||||
data["playlist_id"] = playlist['id']
|
||||
data["transmission_id"] = playlist['schedule_id']
|
||||
except Exception, e:
|
||||
data["playlist_id"] = 0
|
||||
data["user_id"] = 0
|
||||
data["transmission_id"] = 0
|
||||
data = json.write(data)
|
||||
return data
|
||||
|
||||
|
|
|
@ -14,67 +14,12 @@ api_client = "campcaster"
|
|||
# _include_ trailing slash !! #
|
||||
############################################
|
||||
cache_dir = '/opt/pypo/cache/'
|
||||
schedule_dir = '/opt/pypo/cache/schedule'
|
||||
file_dir = '/opt/pypo/files/'
|
||||
tmp_dir = '/opt/pypo/tmp/'
|
||||
|
||||
############################################
|
||||
# API path & co #
|
||||
############################################
|
||||
# Value needed to access the API
|
||||
api_key = 'AAA'
|
||||
|
||||
# Hostname
|
||||
base_url = 'http://localhost/'
|
||||
|
||||
################################################################################
|
||||
# Generic Config - if you are creating a new API client, define these values #
|
||||
################################################################################
|
||||
# Path to the base of the API
|
||||
#api_base = ''
|
||||
|
||||
# URL to get the version number of the API
|
||||
#version_url = ''
|
||||
|
||||
# Schedule export path.
|
||||
# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
#export_url = ''
|
||||
|
||||
# Update whether an item has been played.
|
||||
# %%item_id%%
|
||||
# %%played%%
|
||||
#update_item_url = ''
|
||||
|
||||
# Update whether an item is currently playing.
|
||||
#update_start_playing_url = ''
|
||||
|
||||
# ???
|
||||
#generate_range_url = ''
|
||||
|
||||
|
||||
#####################
|
||||
# Campcaster Config #
|
||||
#####################
|
||||
api_base = 'campcaster/'
|
||||
version_url = 'api/api_version.php?api_key=%%api_key%%'
|
||||
export_url = 'api/schedule.php?from=%%from%%&to=%%to%%&api_key=%%api_key%%'
|
||||
update_item_url = 'api/schedule.php?item_id=%%item_id%%&played=%%played%%'
|
||||
update_start_playing_url = 'api/update_start_playing.php?playlist_type=%%playlist_type%%&export_source=%%export_source%%&media_id=%%media_id%%&playlist_id=%%playlist_id%%&transmission_id=%%transmission_id%%'
|
||||
generate_range_url = 'api/generate_range_dp.php'
|
||||
|
||||
|
||||
##############
|
||||
# OBP config #
|
||||
##############
|
||||
#base_url = 'http://localhost/'
|
||||
#api_base = ''
|
||||
#version_url = 'api/pypo/status/json'
|
||||
#update_item_url = 'api/pypo/update_shedueled_item/$$item_id%%?played=%%played%%'
|
||||
#update_start_playing_url = 'api/pypo/update_start_playing/?playlist_type=%%playlist_type%%&export_source=%%export_source%%&media_id=%%media_id%%&playlist_id=%%playlist_id%%&transmission_id=%%transmission_id%%'
|
||||
#generate_range_url = 'api/pypo/generate_range_dp/'
|
||||
|
||||
|
||||
############################################
|
||||
# Liquidsoap settings #
|
||||
############################################
|
||||
|
@ -87,10 +32,90 @@ ls_port = '1234'
|
|||
prepare_ahead = 24 #in hours
|
||||
cache_for = 24 #how long to hold the cache, in hours
|
||||
|
||||
poll_interval = 10 # in seconds
|
||||
# Poll interval in seconds.
|
||||
#
|
||||
# This is how often the poll script downloads new schedules and files from the
|
||||
# server.
|
||||
#
|
||||
# For production use, this number depends on whether you plan on making any
|
||||
# last-minute changes to your schedule. This number should be set to half of
|
||||
# the time you expect to "lock-in" your schedule. So if your schedule is set
|
||||
# 24 hours in advance, this can be set to poll every 12 hours.
|
||||
#
|
||||
poll_interval = 10 # in seconds.
|
||||
|
||||
|
||||
# Push interval in seconds.
|
||||
#
|
||||
# This is how often the push script checks whether it has something new to
|
||||
# push to liquidsoap.
|
||||
#
|
||||
# It's hard to imagine a situation where this should be more than 1 second.
|
||||
#
|
||||
push_interval = 1 # in seconds
|
||||
|
||||
# 'pre' or 'otf'. 'pre' cues while playlist preparation
|
||||
# while 'otf' (on the fly) cues while loading into ls
|
||||
# (needs the post_processor patch)
|
||||
cue_style = 'pre'
|
||||
|
||||
|
||||
################################################################################
|
||||
# Uncomment *one of the sets* of values from the API clients below, and comment
|
||||
# out all the others.
|
||||
################################################################################
|
||||
|
||||
#####################
|
||||
# Campcaster Config #
|
||||
#####################
|
||||
# Value needed to access the API
|
||||
api_key = 'AAA'
|
||||
|
||||
# Path to the base of the API
|
||||
api_base = 'campcaster/'
|
||||
|
||||
# URL to get the version number of the server API
|
||||
version_url = 'api/api_version.php?api_key=%%api_key%%'
|
||||
|
||||
# Schedule export path.
|
||||
# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
export_url = 'api/schedule.php?from=%%from%%&to=%%to%%&api_key=%%api_key%%'
|
||||
|
||||
# Update whether a schedule group has begun playing.
|
||||
update_item_url = 'api/notify_schedule_group_play.php?schedule_id=%%schedule_id%%'
|
||||
|
||||
# Update whether an audio clip is currently playing.
|
||||
update_start_playing_url = 'api/notify_media_item_start_play.php?media_id=%%media_id%%&schedule_id=%%schedule_id%%'
|
||||
|
||||
# ???
|
||||
generate_range_url = 'api/generate_range_dp.php'
|
||||
|
||||
|
||||
##############
|
||||
# OBP config #
|
||||
##############
|
||||
# Value needed to access the API
|
||||
#api_key = 'AAA'
|
||||
|
||||
#base_url = 'http://localhost/'
|
||||
|
||||
# Path to the base of the API
|
||||
#api_base = ''
|
||||
|
||||
# URL to get the version number of the server API
|
||||
#version_url = 'api/pypo/status/json'
|
||||
|
||||
# Schedule export path.
|
||||
# %%from%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
# %%to%% - starting date/time in the form YYYY-MM-DD-hh-mm
|
||||
|
||||
# Update whether an item has been played.
|
||||
#update_item_url = 'api/pypo/update_shedueled_item/$$item_id%%?played=%%played%%'
|
||||
|
||||
# Update whether an item is currently playing.
|
||||
#update_start_playing_url = 'api/pypo/mod/medialibrary/?playlist_type=%%playlist_type%%&export_source=%%export_source%%&media_id=%%media_id%%&playlist_id=%%playlist_id%%&transmission_id=%%transmission_id%%'
|
||||
|
||||
# ???
|
||||
#generate_range_url = 'api/pypo/generate_range_dp/'
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
"""
|
||||
Python part of radio playout (pypo)
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
"""
|
||||
Python part of radio playout (pypo)
|
||||
|
||||
|
@ -19,7 +17,7 @@ tracks over and over again.
|
|||
|
||||
Attention & ToDos
|
||||
- liquidsoap does not like mono files! So we have to make sure that only files with
|
||||
2 channels are fed to LS
|
||||
2 channels are fed to LiquidSoap
|
||||
(solved: current = audio_to_stereo(current) - maybe not with ultimate performance)
|
||||
|
||||
|
||||
|
@ -74,14 +72,14 @@ parser = OptionParser(usage=usage)
|
|||
parser.add_option("-v", "--compat", help="Check compatibility with server API version", default=False, action="store_true", dest="check_compat")
|
||||
|
||||
parser.add_option("-t", "--test", help="Do a test to make sure everything is working properly.", default=False, action="store_true", dest="test")
|
||||
parser.add_option("-f", "--fetch-scheduler", help="Fetch from scheduler - scheduler (loop, interval in config file)", default=False, action="store_true", dest="fetch_scheduler")
|
||||
parser.add_option("-p", "--push-scheduler", help="Push scheduler to Liquidsoap (loop, interval in config file)", default=False, action="store_true", dest="push_scheduler")
|
||||
parser.add_option("-f", "--fetch-scheduler", help="Fetch the schedule from server. This is a polling process that runs forever.", default=False, action="store_true", dest="fetch_scheduler")
|
||||
parser.add_option("-p", "--push-scheduler", help="Push the schedule to Liquidsoap. This is a polling process that runs forever.", default=False, action="store_true", dest="push_scheduler")
|
||||
|
||||
parser.add_option("-F", "--fetch-daypart", help="Fetch from daypart - scheduler (loop, interval in config file)", default=False, action="store_true", dest="fetch_daypart")
|
||||
parser.add_option("-P", "--push-daypart", help="Push daypart to Liquidsoap (loop, interval in config file)", default=False, action="store_true", dest="push_daypart")
|
||||
|
||||
parser.add_option("-b", "--cleanup", help="Cleanup", default=False, action="store_true", dest="cleanup")
|
||||
parser.add_option("-j", "--jingles", help="Get new jingles from obp, comma separated list if jingle-id's as argument", metavar="LIST")
|
||||
#parser.add_option("-j", "--jingles", help="Get new jingles from server, comma separated list if jingle-id's as argument", metavar="LIST")
|
||||
parser.add_option("-c", "--check", help="Check the cached schedule and exit", default=False, action="store_true", dest="check")
|
||||
|
||||
# parse options
|
||||
|
@ -93,32 +91,19 @@ logging.config.fileConfig("logging.cfg")
|
|||
# loading config file
|
||||
try:
|
||||
config = ConfigObj('config.cfg')
|
||||
CACHE_DIR = config['cache_dir']
|
||||
FILE_DIR = config['file_dir']
|
||||
TMP_DIR = config['tmp_dir']
|
||||
API_BASE = config['api_base']
|
||||
API_KEY = config['api_key']
|
||||
POLL_INTERVAL = float(config['poll_interval'])
|
||||
PUSH_INTERVAL = float(config['push_interval'])
|
||||
LS_HOST = config['ls_host']
|
||||
LS_PORT = config['ls_port']
|
||||
#PREPARE_AHEAD = config['prepare_ahead']
|
||||
CACHE_FOR = config['cache_for']
|
||||
CUE_STYLE = config['cue_style']
|
||||
#print config
|
||||
except Exception, e:
|
||||
print 'Error loading config file: ', e
|
||||
sys.exit()
|
||||
|
||||
#TIME = time.localtime(time.time())
|
||||
TIME = (2010, 6, 26, 15, 33, 23, 2, 322, 0)
|
||||
|
||||
class Global:
|
||||
def __init__(self):
|
||||
print
|
||||
|
||||
def selfcheck(self):
|
||||
self.api_auth = urllib.urlencode({'api_key': API_KEY})
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.api_client.check_version()
|
||||
|
||||
|
@ -128,18 +113,23 @@ class Global:
|
|||
"""
|
||||
class Playout:
|
||||
def __init__(self):
|
||||
self.file_dir = FILE_DIR
|
||||
self.tmp_dir = TMP_DIR
|
||||
self.api_auth = urllib.urlencode({'api_key': API_KEY})
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.cue_file = CueFile()
|
||||
self.silence_file = self.file_dir + 'basic/silence.mp3'
|
||||
|
||||
# set initial state
|
||||
self.silence_file = config["file_dir"] + 'basic/silence.mp3'
|
||||
self.push_ahead = 15
|
||||
self.range_updated = False
|
||||
|
||||
|
||||
def test_api(self):
|
||||
self.api_client.test()
|
||||
|
||||
|
||||
def set_export_source(self, export_source):
|
||||
self.export_source = export_source
|
||||
self.cache_dir = config["cache_dir"] + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule.pickle'
|
||||
self.schedule_tracker_file = self.cache_dir + "schedule_tracker.pickle"
|
||||
|
||||
|
||||
"""
|
||||
Fetching part of pypo
|
||||
|
@ -155,9 +145,7 @@ class Playout:
|
|||
"""
|
||||
logger = logging.getLogger()
|
||||
|
||||
self.export_source = export_source
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
self.set_export_source(export_source)
|
||||
|
||||
try: os.mkdir(self.cache_dir)
|
||||
except Exception, e: pass
|
||||
|
@ -185,10 +173,10 @@ class Playout:
|
|||
except Exception, e: logger.error("%s", e)
|
||||
|
||||
# prepare the playlists
|
||||
if CUE_STYLE == 'pre':
|
||||
try: self.prepare_playlists_cue(self.export_source)
|
||||
if config["cue_style"] == 'pre':
|
||||
try: self.prepare_playlists_cue()
|
||||
except Exception, e: logger.error("%s", e)
|
||||
elif CUE_STYLE == 'otf':
|
||||
elif config["cue_style"] == 'otf':
|
||||
try: self.prepare_playlists(self.export_source)
|
||||
except Exception, e: logger.error("%s", e)
|
||||
|
||||
|
@ -210,10 +198,10 @@ class Playout:
|
|||
|
||||
tnow = time.localtime(time.time())
|
||||
|
||||
if(tnow[3] == 16):
|
||||
if (tnow[3] == 16):
|
||||
self.range_updated = False
|
||||
|
||||
if(tnow[3] == 17 and self.range_updated == False):
|
||||
if (tnow[3] == 17 and self.range_updated == False):
|
||||
try:
|
||||
print self.api_client.generate_range_dp()
|
||||
logger.info("daypart updated")
|
||||
|
@ -248,18 +236,11 @@ class Playout:
|
|||
playlist folder.
|
||||
file is eg 2010-06-23-15-00-00/17_cue_10.132-123.321.mp3
|
||||
"""
|
||||
def prepare_playlists_cue(self, export_source):
|
||||
def prepare_playlists_cue(self):
|
||||
logger = logging.getLogger()
|
||||
|
||||
self.export_source = export_source
|
||||
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
schedule_file.close()
|
||||
except Exception, e:
|
||||
logger.error("%s", e)
|
||||
schedule = None
|
||||
# Load schedule from disk
|
||||
schedule = self.load_schedule()
|
||||
|
||||
# Dont do anything if schedule is empty
|
||||
if (not schedule):
|
||||
|
@ -271,7 +252,6 @@ class Playout:
|
|||
try:
|
||||
for pkey in scheduleKeys:
|
||||
logger.info("found playlist at %s", pkey)
|
||||
#print pkey
|
||||
playlist = schedule[pkey]
|
||||
|
||||
# create playlist directory
|
||||
|
@ -282,18 +262,20 @@ class Playout:
|
|||
|
||||
ls_playlist = '';
|
||||
|
||||
print '*****************************************'
|
||||
print 'pkey: ' + str(pkey)
|
||||
print 'cached at : ' + self.cache_dir + str(pkey)
|
||||
print 'subtype: ' + str(playlist['subtype'])
|
||||
print 'played: ' + str(playlist['played'])
|
||||
print 'schedule id: ' + str(playlist['schedule_id'])
|
||||
print 'duration: ' + str(playlist['duration'])
|
||||
print 'source id: ' + str(playlist['x_ident'])
|
||||
print '*****************************************'
|
||||
logger.debug('*****************************************')
|
||||
logger.debug('pkey: ' + str(pkey))
|
||||
logger.debug('cached at : ' + self.cache_dir + str(pkey))
|
||||
logger.debug('subtype: ' + str(playlist['subtype']))
|
||||
logger.debug('played: ' + str(playlist['played']))
|
||||
logger.debug('schedule id: ' + str(playlist['schedule_id']))
|
||||
logger.debug('duration: ' + str(playlist['duration']))
|
||||
logger.debug('source id: ' + str(playlist['x_ident']))
|
||||
logger.debug('*****************************************')
|
||||
|
||||
# Creating an API call like the next two lines would make this more flexible
|
||||
# mediaType = api_client.get_media_type(playlist)
|
||||
# if (mediaType == PYPO_MEDIA_SKIP):
|
||||
|
||||
#mediaType = api_client.get_media_type(playlist)
|
||||
#if (mediaType == PYPO_MEDIA_SKIP):
|
||||
if int(playlist['played']) == 1:
|
||||
logger.info("playlist %s already played / sent to liquidsoap, so will ignore it", pkey)
|
||||
|
||||
|
@ -401,7 +383,6 @@ class Playout:
|
|||
|
||||
if True == os.access(dst, os.R_OK):
|
||||
# check filesize (avoid zero-byte files)
|
||||
#print 'waiting: ' + dst
|
||||
try: fsize = os.path.getsize(dst)
|
||||
except Exception, e:
|
||||
logger.error("%s", e)
|
||||
|
@ -445,15 +426,11 @@ class Playout:
|
|||
else:
|
||||
if os.path.isfile(dst):
|
||||
logger.debug("file already in cache: %s", dst)
|
||||
#print 'cached'
|
||||
|
||||
else:
|
||||
logger.debug("try to download and cue %s", media['uri'])
|
||||
|
||||
#print '***'
|
||||
dst_tmp = self.tmp_dir + "".join([random.choice(string.letters) for i in xrange(10)]) + '.mp3'
|
||||
#print dst_tmp
|
||||
#print '***'
|
||||
dst_tmp = config["tmp_dir"] + "".join([random.choice(string.letters) for i in xrange(10)]) + '.mp3'
|
||||
self.api_client.get_media(media['uri'], dst_tmp)
|
||||
|
||||
# cue
|
||||
|
@ -509,7 +486,7 @@ class Playout:
|
|||
logger.debug("try to copy and cue %s", media['uri'])
|
||||
|
||||
print '***'
|
||||
dst_tmp = self.tmp_dir + "".join([random.choice(string.letters) for i in xrange(10)])
|
||||
dst_tmp = config["tmp_dir"] + "".join([random.choice(string.letters) for i in xrange(10)])
|
||||
print dst_tmp
|
||||
print '***'
|
||||
|
||||
|
@ -550,10 +527,8 @@ class Playout:
|
|||
"""
|
||||
logger = logging.getLogger()
|
||||
|
||||
self.export_source = export_source
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
offset = 3600 * int(CACHE_FOR)
|
||||
self.set_export_source(export_source)
|
||||
offset = 3600 * int(config["cache_for"])
|
||||
now = time.time()
|
||||
|
||||
for r, d, f in os.walk(self.cache_dir):
|
||||
|
@ -588,128 +563,109 @@ class Playout:
|
|||
def push(self, export_source):
|
||||
logger = logging.getLogger()
|
||||
|
||||
self.export_source = export_source
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
self.set_export_source(export_source)
|
||||
|
||||
self.push_ahead = 15
|
||||
#try:
|
||||
# dummy = self.schedule
|
||||
# logger.debug('schedule already loaded')
|
||||
#except Exception, e:
|
||||
# self.schedule = self.push_init(self.export_source)
|
||||
|
||||
self.schedule = self.load_schedule()
|
||||
playedItems = self.load_schedule_tracker()
|
||||
|
||||
try:
|
||||
dummy = self.schedule
|
||||
logger.debug('schedule already loaded')
|
||||
except Exception, e:
|
||||
self.schedule = self.push_init(self.export_source)
|
||||
|
||||
self.schedule = self.push_init(self.export_source)
|
||||
|
||||
|
||||
"""
|
||||
I'm quite sure that this could be achieved in a much more elegant way in python...
|
||||
"""
|
||||
|
||||
tcomming = time.localtime(time.time() + self.push_ahead)
|
||||
tnow = time.localtime(time.time())
|
||||
|
||||
str_tnow = "%04d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4])
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
str_tcomming = "%04d-%02d-%02d-%02d-%02d" % (tcomming[0], tcomming[1], tcomming[2], tcomming[3], tcomming[4])
|
||||
str_tcomming_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tcomming[0], tcomming[1], tcomming[2], tcomming[3], tcomming[4], tcomming[5])
|
||||
|
||||
#print '--'
|
||||
#print str_tnow_s + ' now'
|
||||
#print str_tcomming_s + ' comming'
|
||||
|
||||
playnow = None
|
||||
|
||||
if self.schedule == None:
|
||||
print 'unable to loop schedule - maybe write in progress'
|
||||
print 'will try in next loop'
|
||||
logger.warn('Unable to loop schedule - maybe write in progress?')
|
||||
logger.warn('Will try again in next loop.')
|
||||
|
||||
else:
|
||||
for pkey in self.schedule:
|
||||
|
||||
for pkey in self.schedule:
|
||||
if pkey[0:16] == str_tcomming:
|
||||
logger.debug('Preparing to push playlist scheduled at: %s', pkey)
|
||||
playlist = self.schedule[pkey]
|
||||
|
||||
if int(playlist['played']) != 1:
|
||||
#print '!!!!!!!!!!!!!!!!!!!'
|
||||
#print 'MATCH'
|
||||
|
||||
"""
|
||||
ok we have a match, replace the current playlist and
|
||||
force liquidsoap to refresh
|
||||
Add a 'played' state to the list in schedule, so it is not called again
|
||||
in the next push loop
|
||||
"""
|
||||
playedFlag = (pkey in playedItems) and playedItems[pkey].get("played", 0)
|
||||
logger.debug("PLAYED FLAG: " + str(playedFlag))
|
||||
if not playedFlag:
|
||||
# We have a match, replace the current playlist and
|
||||
# force liquidsoap to refresh.
|
||||
ptype = playlist['subtype']
|
||||
|
||||
try:
|
||||
user_id = playlist['user_id']
|
||||
playlist_id = playlist['id']
|
||||
transmission_id = playlist['schedule_id']
|
||||
|
||||
except Exception, e:
|
||||
playlist_id = 0
|
||||
user_id = 0
|
||||
transmission_id = 0
|
||||
print e
|
||||
|
||||
#print 'Playlist id:',
|
||||
|
||||
if (self.push_liquidsoap(pkey, ptype, user_id, playlist_id, transmission_id, self.push_ahead) == 1):
|
||||
|
||||
if (self.push_liquidsoap(pkey, self.schedule, ptype) == 1):
|
||||
logger.debug("Pushed to liquidsoap, updating 'played' status.")
|
||||
self.schedule[pkey]['played'] = 1
|
||||
"""
|
||||
Call api to update schedule states and
|
||||
write changes back to cache file
|
||||
"""
|
||||
self.api_client.update_scheduled_item(int(playlist['schedule_id']), 1)
|
||||
schedule_file = open(self.schedule_file, "w")
|
||||
pickle.dump(self.schedule, schedule_file)
|
||||
schedule_file.close()
|
||||
logger.debug("Wrote schedule to disk")
|
||||
|
||||
#else:
|
||||
# print 'Nothing to do...'
|
||||
# Marked the current playlist as 'played' in the schedule tracker
|
||||
# so it is not called again in the next push loop.
|
||||
# Write changes back to tracker file.
|
||||
playedItems[pkey] = playlist
|
||||
playedItems[pkey]['played'] = 1
|
||||
schedule_tracker = open(self.schedule_tracker_file, "w")
|
||||
pickle.dump(playedItems, schedule_tracker)
|
||||
schedule_tracker.close()
|
||||
logger.debug("Wrote schedule to disk: "+str(playedItems))
|
||||
|
||||
# Call API to update schedule states
|
||||
logger.debug("Doing callback to server to update 'played' status.")
|
||||
self.api_client.notify_scheduled_item_start_playing(pkey, self.schedule)
|
||||
|
||||
|
||||
def push_init(self, export_source):
|
||||
def load_schedule(self):
|
||||
logger = logging.getLogger()
|
||||
schedule = None
|
||||
|
||||
self.export_source = export_source
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
|
||||
# load the schedule from cache
|
||||
logger.debug('loading schedule from cache...')
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
schedule_file.close()
|
||||
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
schedule = None
|
||||
# create the file if it doesnt exist
|
||||
if (not os.path.exists(self.schedule_file)):
|
||||
logger.debug('creating file ' + self.schedule_file)
|
||||
open(self.schedule_file, 'w').close()
|
||||
else:
|
||||
# load the schedule from cache
|
||||
logger.debug('loading schedule file '+self.schedule_file)
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
schedule_file.close()
|
||||
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
|
||||
return schedule
|
||||
|
||||
|
||||
def push_liquidsoap(self, pkey, ptype, user_id, playlist_id, transmission_id, push_ahead):
|
||||
def load_schedule_tracker(self):
|
||||
logger = logging.getLogger()
|
||||
playedItems = dict()
|
||||
|
||||
# create the file if it doesnt exist
|
||||
if (not os.path.exists(self.schedule_tracker_file)):
|
||||
logger.debug('creating file ' + self.schedule_tracker_file)
|
||||
schedule_tracker = open(self.schedule_tracker_file, 'w')
|
||||
pickle.dump(playedItems, schedule_tracker)
|
||||
schedule_tracker.close()
|
||||
else:
|
||||
try:
|
||||
logger.debug('loading schedule tracker file '+ self.schedule_tracker_file)
|
||||
schedule_tracker = open(self.schedule_tracker_file, "r")
|
||||
playedItems = pickle.load(schedule_tracker)
|
||||
schedule_tracker.close()
|
||||
except Exception, e:
|
||||
logger.error('Unable to load schedule tracker file: %s', e)
|
||||
|
||||
return playedItems
|
||||
|
||||
|
||||
#self.export_source = export_source
|
||||
|
||||
self.push_ahead = push_ahead
|
||||
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
|
||||
def push_liquidsoap(self, pkey, schedule, ptype):
|
||||
logger = logging.getLogger()
|
||||
|
||||
src = self.cache_dir + str(pkey) + '/list.lsp'
|
||||
|
||||
logger.debug(src)
|
||||
|
||||
try:
|
||||
if True == os.access(src, os.R_OK):
|
||||
logger.debug('OK - Can read playlist file')
|
||||
|
@ -724,8 +680,7 @@ class Playout:
|
|||
if (int(ptype) == 6):
|
||||
tn.write("live_in.start")
|
||||
tn.write("\n")
|
||||
|
||||
|
||||
|
||||
if (int(ptype) < 5):
|
||||
for line in pl_file.readlines():
|
||||
logger.debug(line.strip())
|
||||
|
@ -741,19 +696,11 @@ class Playout:
|
|||
logger.debug('sending "flip"')
|
||||
tn = telnetlib.Telnet(LS_HOST, 1234)
|
||||
|
||||
"""
|
||||
Pass some extra information to liquidsoap
|
||||
"""
|
||||
logger.debug('user_id: %s', user_id)
|
||||
logger.debug('playlist_id: %s', playlist_id)
|
||||
logger.debug('transmission_id: %s', transmission_id)
|
||||
logger.debug('ptype: %s', ptype)
|
||||
|
||||
tn.write("vars.user_id %s\n" % user_id)
|
||||
tn.write("vars.playlist_id %s\n" % playlist_id)
|
||||
tn.write("vars.transmission_id %s\n" % transmission_id)
|
||||
tn.write("vars.playlist_type %s\n" % ptype)
|
||||
|
||||
# Get any extra information for liquidsoap (which will be sent back to us)
|
||||
liquidsoap_data = self.api_client.get_liquidsoap_data(pkey, schedule)
|
||||
logger.debug("Sending additional data to liquidsoap: "+liquidsoap_data)
|
||||
tn.write("vars.pypo_data "+liquidsoap_data+"\n")
|
||||
|
||||
# if(int(ptype) < 5):
|
||||
# tn.write(self.export_source + '.flip')
|
||||
# tn.write("\n")
|
||||
|
@ -761,7 +708,7 @@ class Playout:
|
|||
tn.write(self.export_source + '.flip')
|
||||
tn.write("\n")
|
||||
|
||||
if(int(ptype) == 6):
|
||||
if (int(ptype) == 6):
|
||||
tn.write("live.active 1")
|
||||
tn.write("\n")
|
||||
else:
|
||||
|
@ -772,7 +719,7 @@ class Playout:
|
|||
|
||||
tn.write("exit\n")
|
||||
|
||||
logger.debug(tn.read_all())
|
||||
tn.read_all()
|
||||
status = 1
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
|
@ -857,38 +804,38 @@ class Playout:
|
|||
|
||||
"""
|
||||
Updates the jingles. Give comma separated list of jingle tracks.
|
||||
|
||||
NOTE: commented out because it needs to be converted to use the API client. - Paul
|
||||
"""
|
||||
def update_jingles(self, options):
|
||||
print 'jingles'
|
||||
|
||||
jingle_list = string.split(options, ',')
|
||||
print jingle_list
|
||||
for media_id in jingle_list:
|
||||
# api path maybe should not be hard-coded
|
||||
src = API_BASE + 'api/pypo/get_media/' + str(media_id)
|
||||
print src
|
||||
# include the hourly jungles for the moment
|
||||
dst = "%s%s/%s.mp3" % (self.file_dir, 'jingles/hourly', str(media_id))
|
||||
print dst
|
||||
|
||||
try:
|
||||
print '** urllib auth with: ',
|
||||
print self.api_auth
|
||||
opener = urllib.URLopener()
|
||||
opener.retrieve (src, dst, False, self.api_auth)
|
||||
logger.info("downloaded %s to %s", src, dst)
|
||||
except Exception, e:
|
||||
print e
|
||||
logger.error("%s", e)
|
||||
#def update_jingles(self, options):
|
||||
# print 'jingles'
|
||||
#
|
||||
# jingle_list = string.split(options, ',')
|
||||
# print jingle_list
|
||||
# for media_id in jingle_list:
|
||||
# # api path maybe should not be hard-coded
|
||||
# src = API_BASE + 'api/pypo/get_media/' + str(media_id)
|
||||
# print src
|
||||
# # include the hourly jungles for the moment
|
||||
# dst = "%s%s/%s.mp3" % (config["file_dir"], 'jingles/hourly', str(media_id))
|
||||
# print dst
|
||||
#
|
||||
# try:
|
||||
# print '** urllib auth with: ',
|
||||
# print self.api_auth
|
||||
# opener = urllib.URLopener()
|
||||
# opener.retrieve (src, dst, False, self.api_auth)
|
||||
# logger.info("downloaded %s to %s", src, dst)
|
||||
# except Exception, e:
|
||||
# print e
|
||||
# logger.error("%s", e)
|
||||
|
||||
|
||||
def check_schedule(self, export_source):
|
||||
logger = logging.getLogger()
|
||||
|
||||
self.export_source = export_source
|
||||
self.cache_dir = CACHE_DIR + self.export_source + '/'
|
||||
self.schedule_file = self.cache_dir + 'schedule'
|
||||
|
||||
self.set_export_source(export_source)
|
||||
|
||||
try:
|
||||
schedule_file = open(self.schedule_file, "r")
|
||||
schedule = pickle.load(schedule_file)
|
||||
|
@ -898,11 +845,8 @@ class Playout:
|
|||
logger.error("%s", e)
|
||||
schedule = None
|
||||
|
||||
#for pkey in schedule:
|
||||
for pkey in sorted(schedule.iterkeys()):
|
||||
|
||||
playlist = schedule[pkey]
|
||||
|
||||
print '*****************************************'
|
||||
print '\033[0;32m%s %s\033[m' % ('scheduled at:', str(pkey))
|
||||
print 'cached at : ' + self.cache_dir + str(pkey)
|
||||
|
@ -911,7 +855,6 @@ class Playout:
|
|||
print 'schedule id: ' + str(playlist['schedule_id'])
|
||||
print 'duration: ' + str(playlist['duration'])
|
||||
print 'source id: ' + str(playlist['x_ident'])
|
||||
|
||||
print '-----------------------------------------'
|
||||
|
||||
for media in playlist['medias']:
|
||||
|
@ -921,7 +864,6 @@ class Playout:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print
|
||||
print '###########################################'
|
||||
print '# *** pypo *** #'
|
||||
|
@ -997,11 +939,11 @@ while run == True:
|
|||
time.sleep(PUSH_INTERVAL)
|
||||
|
||||
|
||||
while options.jingles:
|
||||
try: po.update_jingles(options.jingles)
|
||||
except Exception, e:
|
||||
print e
|
||||
sys.exit()
|
||||
#while options.jingles:
|
||||
# try: po.update_jingles(options.jingles)
|
||||
# except Exception, e:
|
||||
# print e
|
||||
# sys.exit()
|
||||
|
||||
|
||||
while options.check:
|
||||
|
@ -1011,7 +953,7 @@ while run == True:
|
|||
sys.exit()
|
||||
|
||||
while options.cleanup:
|
||||
try: po.cleanup()
|
||||
try: po.cleanup('scheduler')
|
||||
except Exception, e:
|
||||
print e
|
||||
sys.exit()
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
"""
|
||||
Python part of radio playout (pypo)
|
||||
|
||||
This function acts as a gateway between liquidsoap and the obp-api.
|
||||
Mainliy used to tell the plattform what pypo/LS does.
|
||||
Mainliy used to tell the platform what pypo/LS does.
|
||||
|
||||
Main case:
|
||||
- whenever Liquidsoap starts playing a new track, its on_metadata callback calls
|
||||
a function in liquidsoap (notify(m)) which then calls the python script here
|
||||
with the currently starting filename as parameter
|
||||
- this python script takes this parameter, tries to extract the actual
|
||||
media id from it, and then calls back to obp via api to tell about
|
||||
|
||||
media id from it, and then calls back to API to tell it about it.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -171,7 +168,6 @@ class Notify:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print
|
||||
print '#########################################'
|
||||
print '# *** pypo *** #'
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
"""
|
||||
Python part of radio playout (pypo)
|
||||
|
||||
This function acts as a gateway between liquidsoap and the obp-api.
|
||||
Mainliy used to tell the plattform what pypo/LS does.
|
||||
This function acts as a gateway between liquidsoap and the server API.
|
||||
Mainly used to tell the platform what pypo/liquidsoap does.
|
||||
|
||||
Main case:
|
||||
- whenever LS starts playing a new track, its on_metadata callback calls
|
||||
a function in ls (notify(m)) which then calls the pythin script here
|
||||
a function in ls (notify(m)) which then calls the python script here
|
||||
with the currently starting filename as parameter
|
||||
- this python script takes this parameter, tries to extract the actual
|
||||
media id from it, and then calls back to obp via api to tell about
|
||||
|
||||
media id from it, and then calls back to the API to tell about it about it.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -52,14 +49,14 @@ usage = "%prog [options]" + " - notification gateway"
|
|||
parser = OptionParser(usage=usage)
|
||||
|
||||
# Options
|
||||
#parser.add_option("-p", "--playing", help="Tell daddy what is playing right now", dest="playing", default=False, metavar=False)
|
||||
parser.add_option("-p", "--playing", help="Tell daddy what is playing right now", default=False, action="store_true", dest="playing")
|
||||
parser.add_option("-t", "--playlist-type", help="Tell daddy what is playing right now", metavar="playlist_type")
|
||||
parser.add_option("-M", "--media-id", help="Tell daddy what is playing right now", metavar="media_id")
|
||||
parser.add_option("-U", "--user-id", help="Tell daddy what is playing right now", metavar="user_id")
|
||||
parser.add_option("-P", "--playlist-id", help="Tell daddy what is playing right now", metavar="playlist_id")
|
||||
parser.add_option("-T", "--transmission-id", help="Tell daddy what is playing right now", metavar="transmission_id")
|
||||
parser.add_option("-E", "--export-source", help="Tell daddy what is playing right now", metavar="export_source")
|
||||
parser.add_option("-d", "--data", help="Pass JSON data from liquidsoap into this script.", metavar="data")
|
||||
#parser.add_option("-p", "--playing", help="Tell server what is playing right now.", default=False, action="store_true", dest="playing")
|
||||
#parser.add_option("-t", "--playlist-type", help="", metavar="playlist_type")
|
||||
parser.add_option("-m", "--media-id", help="ID of the file that is currently playing.", metavar="media_id")
|
||||
#parser.add_option("-U", "--user-id", help="", metavar="user_id")
|
||||
#parser.add_option("-P", "--playlist-id", help="", metavar="playlist_id")
|
||||
#parser.add_option("-T", "--transmission-id", help="", metavar="transmission_id")
|
||||
#parser.add_option("-E", "--export-source", help="", metavar="export_source")
|
||||
|
||||
# parse options
|
||||
(options, args) = parser.parse_args()
|
||||
|
@ -70,10 +67,6 @@ logging.config.fileConfig("logging.cfg")
|
|||
# loading config file
|
||||
try:
|
||||
config = ConfigObj('config.cfg')
|
||||
TMP_DIR = config['tmp_dir']
|
||||
BASE_URL = config['base_url']
|
||||
API_BASE = BASE_URL + 'mod/medialibrary/'
|
||||
API_KEY = config['api_key']
|
||||
|
||||
except Exception, e:
|
||||
print 'error: ', e
|
||||
|
@ -85,144 +78,156 @@ class Global:
|
|||
print
|
||||
|
||||
def selfcheck(self):
|
||||
|
||||
self.api_auth = urllib.urlencode({'api_key': API_KEY})
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.api_client.check_version()
|
||||
pass
|
||||
#self.api_client = api_client.api_client_factory(config)
|
||||
#self.api_client.check_version()
|
||||
|
||||
class Notify:
|
||||
def __init__(self):
|
||||
self.tmp_dir = TMP_DIR
|
||||
self.api_auth = urllib.urlencode({'api_key': API_KEY})
|
||||
self.api_client = api_client.api_client_factory(config)
|
||||
self.dls_client = DlsClient('127.0.0.128', 50008, 'myusername', 'mypass')
|
||||
#self.dls_client = DlsClient('127.0.0.128', 50008, 'myusername', 'mypass')
|
||||
|
||||
|
||||
def start_playing(self, options):
|
||||
logger = logging.getLogger("start_playing")
|
||||
tnow = time.localtime(time.time())
|
||||
def notify_media_start_playing(self, data, media_id):
|
||||
logger = logging.getLogger()
|
||||
#tnow = time.localtime(time.time())
|
||||
|
||||
#print options
|
||||
|
||||
print '#################################################'
|
||||
print '# calling obp to tell about what\'s playing #'
|
||||
print '#################################################'
|
||||
|
||||
if int(options.playlist_type) < 5:
|
||||
print 'seems to be a playlist'
|
||||
|
||||
try:
|
||||
media_id = int(options.media_id)
|
||||
except Exception, e:
|
||||
media_id = 0
|
||||
|
||||
response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
||||
|
||||
print response
|
||||
|
||||
if int(options.playlist_type) == 6:
|
||||
print 'seems to be a couchcast'
|
||||
|
||||
try:
|
||||
media_id = int(options.media_id)
|
||||
except Exception, e:
|
||||
media_id = 0
|
||||
|
||||
response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
||||
|
||||
print response
|
||||
|
||||
sys.exit()
|
||||
logger.debug('#################################################')
|
||||
logger.debug('# Calling server to update about what\'s playing #')
|
||||
logger.debug('#################################################')
|
||||
logger.debug('data = '+ str(data))
|
||||
#print 'options.data = '+ options.data
|
||||
#data = json.read(options.data)
|
||||
response = self.api_client.notify_media_item_start_playing(data, media_id)
|
||||
logger.debug("Response: "+str(response))
|
||||
|
||||
#def start_playing(self, options):
|
||||
# logger = logging.getLogger("start_playing")
|
||||
# tnow = time.localtime(time.time())
|
||||
#
|
||||
# #print options
|
||||
#
|
||||
# logger.debug('#################################################')
|
||||
# logger.debug('# Calling server to update about what\'s playing #')
|
||||
# logger.debug('#################################################')
|
||||
#
|
||||
# if int(options.playlist_type) < 5:
|
||||
# logger.debug('seems to be a playlist')
|
||||
#
|
||||
# try:
|
||||
# media_id = int(options.media_id)
|
||||
# except Exception, e:
|
||||
# media_id = 0
|
||||
#
|
||||
# response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
||||
#
|
||||
# logger.debug(response)
|
||||
#
|
||||
# if int(options.playlist_type) == 6:
|
||||
# logger.debug('seems to be a couchcast')
|
||||
#
|
||||
# try:
|
||||
# media_id = int(options.media_id)
|
||||
# except Exception, e:
|
||||
# media_id = 0
|
||||
#
|
||||
# response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
||||
#
|
||||
# logger.debug(response)
|
||||
#
|
||||
# sys.exit()
|
||||
|
||||
def start_playing_legacy(self, options):
|
||||
logger = logging.getLogger("start_playing")
|
||||
tnow = time.localtime(time.time())
|
||||
|
||||
print '#################################################'
|
||||
print '# calling obp to tell about what\'s playing #'
|
||||
print '#################################################'
|
||||
|
||||
path = options
|
||||
|
||||
print
|
||||
print path
|
||||
print
|
||||
|
||||
if 'pl_id' in path:
|
||||
print 'seems to be a playlist'
|
||||
type = 'playlist'
|
||||
id = path[5:]
|
||||
|
||||
elif 'text' in path:
|
||||
print 'seems to be a playlist'
|
||||
type = 'text'
|
||||
id = path[4:]
|
||||
print id
|
||||
|
||||
else:
|
||||
print 'seems to be a single track (media)'
|
||||
type = 'media'
|
||||
try:
|
||||
file = path.split("/")[-1:][0]
|
||||
if file.find('_cue_') > 0:
|
||||
id = file.split("_cue_")[0]
|
||||
else:
|
||||
id = file.split(".")[-2:][0]
|
||||
|
||||
except Exception, e:
|
||||
#print e
|
||||
id = False
|
||||
|
||||
try:
|
||||
id = id
|
||||
except Exception, e:
|
||||
#print e
|
||||
id = False
|
||||
|
||||
print
|
||||
print type + " id: ",
|
||||
print id
|
||||
|
||||
|
||||
response = self.api_client.update_start_playing(type, id, self.export_source, path)
|
||||
|
||||
print 'DONE'
|
||||
|
||||
try:
|
||||
txt = response['txt']
|
||||
print '#######################################'
|
||||
print txt
|
||||
print '#######################################'
|
||||
#self.dls_client.set_txt(txt)
|
||||
|
||||
except Exception, e:
|
||||
print e
|
||||
#def start_playing_legacy(self, options):
|
||||
# logger = logging.getLogger("start_playing")
|
||||
# tnow = time.localtime(time.time())
|
||||
#
|
||||
# print '#################################################'
|
||||
# print '# Calling server to update about what\'s playing #'
|
||||
# print '#################################################'
|
||||
#
|
||||
# path = options
|
||||
#
|
||||
# print
|
||||
# print path
|
||||
# print
|
||||
#
|
||||
# if 'pl_id' in path:
|
||||
# print 'seems to be a playlist'
|
||||
# type = 'playlist'
|
||||
# id = path[5:]
|
||||
#
|
||||
# elif 'text' in path:
|
||||
# print 'seems to be a playlist'
|
||||
# type = 'text'
|
||||
# id = path[4:]
|
||||
# print id
|
||||
#
|
||||
# else:
|
||||
# print 'seems to be a single track (media)'
|
||||
# type = 'media'
|
||||
# try:
|
||||
# file = path.split("/")[-1:][0]
|
||||
# if file.find('_cue_') > 0:
|
||||
# id = file.split("_cue_")[0]
|
||||
# else:
|
||||
# id = file.split(".")[-2:][0]
|
||||
#
|
||||
# except Exception, e:
|
||||
# #print e
|
||||
# id = False
|
||||
#
|
||||
# try:
|
||||
# id = id
|
||||
# except Exception, e:
|
||||
# #print e
|
||||
# id = False
|
||||
#
|
||||
# print
|
||||
# print type + " id: ",
|
||||
# print id
|
||||
#
|
||||
#
|
||||
# response = self.api_client.update_start_playing(type, id, self.export_source, path)
|
||||
#
|
||||
# print 'DONE'
|
||||
#
|
||||
# try:
|
||||
# txt = response['txt']
|
||||
# print '#######################################'
|
||||
# print txt
|
||||
# print '#######################################'
|
||||
# #self.dls_client.set_txt(txt)
|
||||
#
|
||||
# except Exception, e:
|
||||
# print e
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print
|
||||
print '#########################################'
|
||||
print '# *** pypo *** #'
|
||||
print '# pypo notification gateway #'
|
||||
print '#########################################'
|
||||
print
|
||||
|
||||
# initialize
|
||||
g = Global()
|
||||
g.selfcheck()
|
||||
n = Notify()
|
||||
|
||||
|
||||
run = True
|
||||
while run == True:
|
||||
logger = logging.getLogger("pypo notify")
|
||||
|
||||
if options.playing:
|
||||
try: n.start_playing(options)
|
||||
except Exception, e:
|
||||
print e
|
||||
sys.exit()
|
||||
|
||||
sys.exit()
|
||||
logger = logging.getLogger()
|
||||
#if options.playing:
|
||||
# try: n.start_playing(options)
|
||||
# except Exception, e:
|
||||
# print e
|
||||
# sys.exit()
|
||||
if not options.data:
|
||||
print "NOTICE: 'data' command-line argument not given."
|
||||
sys.exit()
|
||||
|
||||
if not options.media_id:
|
||||
print "NOTICE: 'media_id' command-line argument not given."
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
g.selfcheck()
|
||||
n = Notify()
|
||||
n.notify_media_start_playing(options.data, options.media_id)
|
||||
except Exception, e:
|
||||
print e
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
|
||||
"""
|
||||
cue script that gets called by liquidsoap if a file in the playlist
|
||||
|
|
|
@ -6,7 +6,11 @@ playlist_id = ref '0'
|
|||
user_id = ref '0'
|
||||
transmission_id = ref '0'
|
||||
playlist_type = ref '0'
|
||||
pypo_data = ref '0'
|
||||
|
||||
def set_pypo_data(s)
|
||||
pypo_data := s
|
||||
end
|
||||
|
||||
def set_user_id(s)
|
||||
user_id := s
|
||||
|
@ -29,4 +33,5 @@ end
|
|||
server.register(namespace="vars", "user_id", fun (s) -> begin set_user_id(s) "Done!" end)
|
||||
server.register(namespace="vars", "playlist_id", fun (s) -> begin set_playlist_id(s) "Done!" end)
|
||||
server.register(namespace="vars", "transmission_id", fun (s) -> begin set_transmission_id(s) "Done!" end)
|
||||
server.register(namespace="vars", "playlist_type", fun (s) -> begin set_playlist_type(s) "Done!" end)
|
||||
server.register(namespace="vars", "playlist_type", fun (s) -> begin set_playlist_type(s) "Done!" end)
|
||||
server.register(namespace="vars", "pypo_data", fun (s) -> begin set_pypo_data(s) "Done!" end)
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
def notify(m)
|
||||
|
||||
print('user_id: #{!user_id}')
|
||||
print('playlist_id: #{!playlist_id}')
|
||||
print('transmission_id: #{!transmission_id}')
|
||||
print('playlist_type: #{!playlist_type}')
|
||||
# print('user_id: #{!user_id}')
|
||||
# print('playlist_id: #{!playlist_id}')
|
||||
# print('transmission_id: #{!transmission_id}')
|
||||
# print('playlist_type: #{!playlist_type}')
|
||||
|
||||
if !playlist_type=='5' then
|
||||
print('livesession')
|
||||
|
@ -20,8 +20,9 @@ def notify(m)
|
|||
end
|
||||
|
||||
if !playlist_type=='0' or !playlist_type=='1' or !playlist_type=='2' or !playlist_type=='3' or !playlist_type=='4' then
|
||||
print('playlist')
|
||||
system("./notify.sh --playing --playlist-type=#{!playlist_type} --media-id=#{m['media_id']} --export-source=#{m['export_source']}")
|
||||
print('include_notify.liq: notify on playlist')
|
||||
#system("./notify.sh --playing --playlist-type=#{!playlist_type} --media-id=#{m['media_id']} --export-source=#{m['export_source']}")
|
||||
system("./notify.sh --data='#{!pypo_data}' --media-id=#{m['media_id']}")
|
||||
end
|
||||
|
||||
end
|
|
@ -2,9 +2,6 @@
|
|||
# liquidsoap config file #
|
||||
###########################################
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
|
||||
# this file is specific to the obp
|
||||
# installation. eg it assumes that there are
|
||||
# two instances of LS running
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
# Register the cut protocol
|
||||
def cue_protocol(arg,delay)
|
||||
# The extraction program
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# author Jonas Ohrstrom <jonas@digris.ch>
|
||||
|
||||
import sys
|
||||
import shutil
|
||||
import random
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
require_once('../conf.php');
|
||||
require_once('DB.php');
|
||||
require_once('../backend/StoredFile.php');
|
||||
|
||||
$api_key = $_GET['api_key'];
|
||||
|
@ -13,13 +12,6 @@ if(!in_array($api_key, $CC_CONFIG["apiKey"]))
|
|||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
$CC_DBC = DB::connect($CC_CONFIG['dsn'], TRUE);
|
||||
if (PEAR::isError($CC_DBC)) {
|
||||
echo "ERROR: ".$CC_DBC->getMessage()." ".$CC_DBC->getUserInfo()."\n";
|
||||
exit(1);
|
||||
}
|
||||
$CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC);
|
||||
|
||||
$filename = $_GET["file"];
|
||||
$file_id = substr($filename, 0, strpos($filename, "."));
|
||||
if (ctype_alnum($file_id) && strlen($file_id) == 32) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
require_once('../conf.php');
|
||||
require_once('../backend/Schedule.php');
|
||||
|
||||
$api_key = $_GET['api_key'];
|
||||
if(!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||
{
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
print 'You are not allowed to access this resource.';
|
||||
exit;
|
||||
}
|
||||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
$schedule_group_id = $_GET["schedule_id"];
|
||||
$media_id = $_GET["media_id"];
|
||||
$f = StoredFile::RecallByGunid($media_id);
|
||||
|
||||
if (is_numeric($schedule_group_id)) {
|
||||
$sg = new ScheduleGroup($schedule_group_id);
|
||||
if ($sg->exists()) {
|
||||
$result = $sg->notifyMediaItemStartPlay($f->getId());
|
||||
if (!PEAR::isError($result)) {
|
||||
echo json_encode(array("status"=>1, "message"=>""));
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message"=>"DB Error:".$result->getMessage()));
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message"=>"Schedule group does not exist: ".$schedule_group_id));
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message" => "Incorrect or non-numeric arguments given."));
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
require_once('../conf.php');
|
||||
require_once('../backend/Schedule.php');
|
||||
|
||||
$api_key = $_GET['api_key'];
|
||||
if (!in_array($api_key, $CC_CONFIG["apiKey"]))
|
||||
{
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
print 'You are not allowed to access this resource.';
|
||||
exit;
|
||||
}
|
||||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
$schedule_group_id = $_GET["schedule_id"];
|
||||
if (is_numeric($schedule_group_id)) {
|
||||
$sg = new ScheduleGroup($schedule_group_id);
|
||||
if ($sg->exists()) {
|
||||
$result = $sg->notifyGroupStartPlay();
|
||||
if (!PEAR::isError($result)) {
|
||||
echo json_encode(array("status"=>1, "message"=>""));
|
||||
exit;
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message"=>"DB Error:".$result->getMessage()));
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message"=>"Schedule group does not exist: ".$schedule_group_id));
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
echo json_encode(array("status"=>0, "message"=>"Incorrect or non-numeric arguments given."));
|
||||
exit;
|
||||
}
|
||||
?>
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
require_once('../conf.php');
|
||||
require_once('DB.php');
|
||||
require_once('../backend/Schedule.php');
|
||||
|
||||
$api_key = $_GET['api_key'];
|
||||
|
@ -13,12 +12,6 @@ if(!in_array($api_key, $CC_CONFIG["apiKey"]))
|
|||
|
||||
PEAR::setErrorHandling(PEAR_ERROR_RETURN);
|
||||
|
||||
$CC_DBC = DB::connect($CC_CONFIG['dsn'], TRUE);
|
||||
if (PEAR::isError($CC_DBC)) {
|
||||
echo "ERROR: ".$CC_DBC->getMessage()." ".$CC_DBC->getUserInfo()."\n";
|
||||
exit(1);
|
||||
}
|
||||
$CC_DBC->setFetchMode(DB_FETCHMODE_ASSOC);
|
||||
$from = $_GET["from"];
|
||||
$to = $_GET["to"];
|
||||
echo Schedule::ExportRangeAsJson($from, $to);
|
||||
|
|
|
@ -10,6 +10,21 @@ class ScheduleGroup {
|
|||
$this->groupId = $p_groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the schedule group exists in the DB.
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists() {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "SELECT COUNT(*) FROM ".$CC_CONFIG['scheduleTable']
|
||||
." WHERE group_id=".$this->groupId;
|
||||
$result = $CC_DBC->GetOne($sql);
|
||||
if (PEAR::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return $result != "0";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a date to an ID by stripping out all characters
|
||||
* and padding with zeros.
|
||||
|
@ -204,6 +219,22 @@ class ScheduleGroup {
|
|||
// $sql = "UPDATE ".$CC_CONFIG["scheduleTable"]. " SET id=, starts=,ends="
|
||||
}
|
||||
|
||||
public function notifyGroupStartPlay() {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "UPDATE ".$CC_CONFIG['scheduleTable']
|
||||
." SET schedule_group_played=TRUE"
|
||||
." WHERE group_id=".$this->groupId;
|
||||
return $CC_DBC->query($sql);
|
||||
}
|
||||
|
||||
public function notifyMediaItemStartPlay($p_fileId) {
|
||||
global $CC_CONFIG, $CC_DBC;
|
||||
$sql = "UPDATE ".$CC_CONFIG['scheduleTable']
|
||||
." SET media_item_played=TRUE"
|
||||
." WHERE group_id=".$this->groupId
|
||||
." AND file_id=".pg_escape_string($p_fileId);
|
||||
return $CC_DBC->query($sql);
|
||||
}
|
||||
}
|
||||
|
||||
class Schedule {
|
||||
|
@ -464,7 +495,7 @@ class Schedule {
|
|||
$playlists[$pkey]['user_id'] = 0;
|
||||
$playlists[$pkey]['id'] = $dx["playlist_id"];
|
||||
$playlists[$pkey]['start'] = Schedule::CcTimeToPypoTime($dx["start"]);
|
||||
$playlists[$pkey]['end'] = Schedule::CcTimeToPypoTime($dx["end"]);
|
||||
$playlists[$pkey]['end'] = Schedule::CcTimeToPypoTime($dx["end"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -244,6 +244,8 @@ CREATE TABLE "cc_schedule"
|
|||
"fade_out" TIME default '00:00:00',
|
||||
"cue_in" TIME default '00:00:00',
|
||||
"cue_out" TIME default '00:00:00',
|
||||
"schedule_group_played" BOOLEAN default 'f',
|
||||
"media_item_played" BOOLEAN default 'f',
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
|
|
|
@ -182,6 +182,8 @@
|
|||
<column name="fade_out" phpName="FadeOut" type="TIME" required="false" defaultValue="00:00:00"/>
|
||||
<column name="cue_in" phpName="CueIn" type="TIME" required="false" defaultValue="00:00:00"/>
|
||||
<column name="cue_out" phpName="CueOut" type="TIME" required="false" defaultValue="00:00:00"/>
|
||||
<column name="schedule_group_played" phpName="ScheduleGroupPlayed" type="BOOLEAN" required="false" defaultValue="0"/>
|
||||
<column name="media_item_played" phpName="MediaItemPlayed" type="BOOLEAN" required="false" defaultValue="0"/>
|
||||
</table>
|
||||
<table name="cc_sess" phpName="CcSess">
|
||||
<column name="sessid" phpName="Sessid" type="CHAR" size="32" primaryKey="true" required="true"/>
|
||||
|
|
|
@ -31,11 +31,26 @@ $pl = new Playlist();
|
|||
$pl->create($playlistName);
|
||||
|
||||
// Add a media clip
|
||||
$mediaFile = StoredFile::findByOriginalName("test10001.mp3");
|
||||
$mediaFile = StoredFile::findByOriginalName("Manolo Camp - Morning Coffee.mp3");
|
||||
if (is_null($mediaFile)) {
|
||||
echo "Adding test audio clip to the database.\n";
|
||||
$v = array("filepath" => __DIR__."/test10001.mp3");
|
||||
$v = array("filepath" => __DIR__."/../../audio_samples/OpSound/Manolo Camp - Morning Coffee.mp3");
|
||||
$mediaFile = StoredFile::Insert($v);
|
||||
if (PEAR::isError($mediaFile)) {
|
||||
var_dump($mediaFile);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
$pl->addAudioClip($mediaFile->getId());
|
||||
$mediaFile = StoredFile::findByOriginalName("Peter Rudenko - Opening.mp3");
|
||||
if (is_null($mediaFile)) {
|
||||
echo "Adding test audio clip to the database.\n";
|
||||
$v = array("filepath" => __DIR__."/../../audio_samples/OpSound/Peter Rudenko - Opening.mp3");
|
||||
$mediaFile = StoredFile::Insert($v);
|
||||
if (PEAR::isError($mediaFile)) {
|
||||
var_dump($mediaFile);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
$pl->addAudioClip($mediaFile->getId());
|
||||
echo "done.\n";
|
||||
|
|
Loading…
Reference in New Issue