cc-2015: on reboot resume show
-liquidsoap is having some problems with cue points right now need to check if this is my fault.
This commit is contained in:
parent
e5ed11ee51
commit
e90e6d7c12
|
@ -1,4 +1,5 @@
|
|||
|
||||
SUBDIRS = tests
|
||||
DISTFILES = $(wildcard *.in) Makefile ask-liquidsoap.rb ask-liquidsoap.pl \
|
||||
$(wildcard *.liq) extract-replaygain
|
||||
|
||||
|
|
|
@ -9,37 +9,43 @@ my_get_mime = get_mime
|
|||
get_mime = my_get_mime
|
||||
|
||||
%ifdef add_decoder
|
||||
if test_process("which flac") then
|
||||
log(level=3,"Found flac binary: enabling flac external decoder.")
|
||||
flac_p = "flac -d -c - 2>/dev/null"
|
||||
def test_flac(file) =
|
||||
if test_process("which metaflac") then
|
||||
channels = list.hd(get_process_lines("metaflac \
|
||||
--show-channels #{quote(file)} \
|
||||
2>/dev/null"))
|
||||
# If the value is not an int, this returns 0 and we are ok :)
|
||||
int_of_string(channels)
|
||||
else
|
||||
# Try to detect using mime test..
|
||||
mime = get_mime(file)
|
||||
if string.match(pattern="flac",file) then
|
||||
# We do not know the number of audio channels
|
||||
# so setting to -1
|
||||
(-1)
|
||||
# Enable external FLAC decoders. Requires flac binary
|
||||
# in the path for audio decoding and metaflac binary for
|
||||
# metadata. Does not work on Win32. Default: disabled.
|
||||
# Please note that built-in support for FLAC is available
|
||||
# in liquidsoap if compiled and should be preferred over
|
||||
# the external decoder.
|
||||
# @category Liquidsoap
|
||||
def enable_external_flac_decoder() =
|
||||
if test_process("which flac") then
|
||||
log(level=3,"Found flac binary: enabling flac external decoder.")
|
||||
flac_p = "flac -d -c - 2>/dev/null"
|
||||
def test_flac(file) =
|
||||
if test_process("which metaflac") then
|
||||
channels = list.hd(get_process_lines("metaflac \
|
||||
--show-channels #{quote(file)} \
|
||||
2>/dev/null"))
|
||||
# If the value is not an int, this returns 0 and we are ok :)
|
||||
int_of_string(channels)
|
||||
else
|
||||
# All tests failed: no audio decodable using flac..
|
||||
0
|
||||
# Try to detect using mime test..
|
||||
mime = get_mime(file)
|
||||
if string.match(pattern="flac",file) then
|
||||
# We do not know the number of audio channels
|
||||
# so setting to -1
|
||||
(-1)
|
||||
else
|
||||
# All tests failed: no audio decodable using flac..
|
||||
0
|
||||
end
|
||||
end
|
||||
end
|
||||
add_decoder(name="FLAC",description="Decode files using the flac \
|
||||
decoder binary.", test=test_flac,flac_p)
|
||||
else
|
||||
log(level=3,"Did not find flac binary: flac decoder disabled.")
|
||||
end
|
||||
add_decoder(name="FLAC",description="Decode files using the flac \
|
||||
decoder binary.", test=test_flac,flac_p)
|
||||
else
|
||||
log(level=3,"Did not find flac binary: flac decoder disabled.")
|
||||
end
|
||||
%endif
|
||||
|
||||
if os.type != "Win32" then
|
||||
if test_process("which metaflac") then
|
||||
log(level=3,"Found metaflac binary: enabling flac external metadata \
|
||||
resolver.")
|
||||
|
@ -55,49 +61,59 @@ if os.type != "Win32" then
|
|||
if list.length(l) >= 1 then
|
||||
list.append([(list.hd(l),"")],l')
|
||||
else
|
||||
l'
|
||||
end
|
||||
l'
|
||||
end
|
||||
end
|
||||
list.fold(f,[],ret)
|
||||
end
|
||||
list.fold(f,[],ret)
|
||||
end
|
||||
add_metadata_resolver("FLAC",flac_meta)
|
||||
else
|
||||
log(level=3,"Did not find metaflac binary: flac metadata resolver disabled.")
|
||||
log(level=3,"Did not find metaflac binary: flac metadata resolver disabled.")
|
||||
end
|
||||
end
|
||||
%endif
|
||||
|
||||
# A list of know extensions and content-type for AAC.
|
||||
# Values from http://en.wikipedia.org/wiki/Advanced_Audio_Coding
|
||||
# TODO: can we register a setting for that ??
|
||||
aac_mimes =
|
||||
["audio/aac", "audio/aacp", "audio/3gpp", "audio/3gpp2", "audio/mp4",
|
||||
"audio/MP4A-LATM", "audio/mpeg4-generic", "audio/x-hx-aac-adts"]
|
||||
aac_filexts = ["m4a", "m4b", "m4p", "m4v",
|
||||
"m4r", "3gp", "mp4", "aac"]
|
||||
%ifdef add_oblivious_decoder
|
||||
# Enable or disable external FAAD (AAC/AAC+/M4A) decoders.
|
||||
# Requires faad binary in the path for audio decoding and
|
||||
# metaflac binary for metadata. Does not work on Win32.
|
||||
# Please note that built-in support for faad is available
|
||||
# in liquidsoap if compiled and should be preferred over
|
||||
# the external decoder.
|
||||
# @category Liquidsoap
|
||||
def enable_external_faad_decoder() =
|
||||
|
||||
# Faad is not very selective so
|
||||
# We are checking only file that
|
||||
# end with a known extension or mime type
|
||||
def faad_test(file) =
|
||||
# Get the file's mime
|
||||
mime = get_mime(file)
|
||||
# Test mime
|
||||
if list.mem(mime,aac_mimes) then
|
||||
true
|
||||
else
|
||||
# Otherwise test file extension
|
||||
ret = string.extract(pattern='\.(.+)$',file)
|
||||
# A list of know extensions and content-type for AAC.
|
||||
# Values from http://en.wikipedia.org/wiki/Advanced_Audio_Coding
|
||||
# TODO: can we register a setting for that ??
|
||||
aac_mimes =
|
||||
["audio/aac", "audio/aacp", "audio/3gpp", "audio/3gpp2", "audio/mp4",
|
||||
"audio/MP4A-LATM", "audio/mpeg4-generic", "audio/x-hx-aac-adts"]
|
||||
aac_filexts = ["m4a", "m4b", "m4p", "m4v",
|
||||
"m4r", "3gp", "mp4", "aac"]
|
||||
|
||||
# Faad is not very selective so
|
||||
# We are checking only file that
|
||||
# end with a known extension or mime type
|
||||
def faad_test(file) =
|
||||
# Get the file's mime
|
||||
mime = get_mime(file)
|
||||
# Test mime
|
||||
if list.mem(mime,aac_mimes) then
|
||||
true
|
||||
else
|
||||
# Otherwise test file extension
|
||||
ret = string.extract(pattern='\.(.+)$',file)
|
||||
if list.length(ret) != 0 then
|
||||
ext = ret["1"]
|
||||
list.mem(ext,aac_filexts)
|
||||
else
|
||||
false
|
||||
end
|
||||
ext = ret["1"]
|
||||
list.mem(ext,aac_filexts)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if os.type != "Win32" then
|
||||
if test_process("which faad") then
|
||||
log(level=3,"Found faad binary: enabling external faad decoder and \
|
||||
metadata resolver.")
|
||||
|
@ -120,15 +136,13 @@ if os.type != "Win32" then
|
|||
0
|
||||
end
|
||||
end
|
||||
%ifdef add_oblivious_decoder
|
||||
add_oblivious_decoder(name="FAAD",description="Decode files using \
|
||||
the faad binary.", test=test_faad, faad_p)
|
||||
%endif
|
||||
def faad_meta(file) =
|
||||
if faad_test(file) then
|
||||
ret = get_process_lines("faad -i \
|
||||
#{quote(file)} 2>&1")
|
||||
# Yea, this is tuff programming (again) !
|
||||
# Yea, this is ugly programming (again) !
|
||||
def get_meta(l,s)=
|
||||
ret = string.extract(pattern="^(\w+):\s(.+)$",s)
|
||||
if list.length(ret) > 0 then
|
||||
|
@ -147,6 +161,7 @@ if os.type != "Win32" then
|
|||
log(level=3,"Did not find faad binary: faad decoder disabled.")
|
||||
end
|
||||
end
|
||||
%endif
|
||||
|
||||
# Standard function for displaying metadata.
|
||||
# Shows artist and title, using "Unknown" when a field is empty.
|
||||
|
@ -189,3 +204,22 @@ def notify_metadata(~urgency="low",~icon="stock_smiley-22",~time=3000,
|
|||
^ ' -t #{time} #{quote(title)} '
|
||||
on_metadata(fun (m) -> system(send^quote(display(m))),s)
|
||||
end
|
||||
|
||||
%ifdef input.external
|
||||
# Stream data from mplayer
|
||||
# @category Source / Input
|
||||
# @param s data URI.
|
||||
# @param ~restart restart on exit.
|
||||
# @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.
|
||||
def input.mplayer(~id="input.mplayer",
|
||||
~restart=true,~restart_on_error=false,
|
||||
~buffer=0.2,~max=10.,s) =
|
||||
input.external(id=id,restart=restart,
|
||||
restart_on_error=restart_on_error,
|
||||
buffer=buffer,max=max,
|
||||
"mplayer -really-quiet -ao pcm:file=/dev/stdout \
|
||||
-vc null -vo null #{quote(s)} 2>/dev/null")
|
||||
end
|
||||
%endif
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
set("log.file",false)
|
||||
|
||||
echo = fun (x) -> system("echo "^quote(x))
|
||||
|
||||
def test(lbl,f)
|
||||
if f() then echo(lbl) else system("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)
|
||||
print(f(14))
|
|
@ -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.
|
||||
|
||||
set("log.file",false)
|
||||
|
||||
# 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))}")
|
||||
|
||||
echo("bla")
|
||||
echo((1,3.12))
|
||||
echo(1 + 1)
|
||||
echo(1. + 2.14)
|
||||
|
||||
# string is not a Num
|
||||
# echo("bl"+"a")
|
||||
|
||||
echo(1 <= 2)
|
||||
echo((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
|
|
@ -300,6 +300,25 @@ def server.insert_metadata(~id="",s) =
|
|||
s
|
||||
end
|
||||
|
||||
# Register a command that outputs the RMS of the returned source.
|
||||
# @category Source / Visualization
|
||||
# @param ~id Force the value of the source ID.
|
||||
def server.rms(~id="",s) =
|
||||
x = rms(id=id,s)
|
||||
rms = fst(x)
|
||||
s = snd(x)
|
||||
id = source.id(s)
|
||||
def rms(_) =
|
||||
rms = rms()
|
||||
"#{rms}"
|
||||
end
|
||||
server.register(namespace="#{id}",
|
||||
description="Return the current RMS of the source.",
|
||||
usage="rms",
|
||||
"rms",rms)
|
||||
s
|
||||
end
|
||||
|
||||
# Get the base name of a path.
|
||||
# Implemented using the corresponding shell command.
|
||||
# @category System
|
||||
|
@ -479,59 +498,95 @@ def smart_crossfade (~start_next=5.,~fade_in=3.,~fade_out=3.,
|
|||
end
|
||||
|
||||
# Custom playlist source written using the script language.
|
||||
# Will read directory or playlist, play all files and stop
|
||||
# Will read directory or playlist, play all files and stop.
|
||||
# Returns a pair @(reload,source)@ where @reload@ is a function
|
||||
# of type @(?uri:string)->unit@ used to reload the source and @source@
|
||||
# is the actual source. The reload function can optionally be called
|
||||
# with a new playlist URI. Otherwise, it reloads the previous URI.
|
||||
# @category Source / Input
|
||||
# @param ~id Force the value of the source ID.
|
||||
# @param ~random Randomize playlist content
|
||||
# @param ~on_done Function to execute when the playlist is finished
|
||||
# @param uri Playlist URI
|
||||
def playlist.once(~random=false,~on_done={()},uri)
|
||||
x = ref 0
|
||||
def playlist.custom(files)
|
||||
length = list.length(files)
|
||||
if length == 0 then
|
||||
log("Empty playlist..")
|
||||
fail ()
|
||||
else
|
||||
files =
|
||||
if random then
|
||||
list.sort(fun (x,y) -> int_of_float(random.float()), files)
|
||||
else
|
||||
files
|
||||
end
|
||||
def next () =
|
||||
state = !x
|
||||
file =
|
||||
if state < length then
|
||||
x := state + 1
|
||||
list.nth(files,state)
|
||||
else
|
||||
# Playlist finished
|
||||
def playlist.reloadable(~id="",~random=false,~on_done={()},uri)
|
||||
# A reference to the playlist
|
||||
playlist = ref []
|
||||
# A reference to the uri
|
||||
playlist_uri = ref uri
|
||||
# A reference to know if the source
|
||||
# has been stopped
|
||||
has_stopped = ref false
|
||||
# The next function
|
||||
def next () =
|
||||
file =
|
||||
if list.length(!playlist) > 0 then
|
||||
ret = list.hd(!playlist)
|
||||
playlist := list.tl(!playlist)
|
||||
ret
|
||||
else
|
||||
# Playlist finished
|
||||
if not !has_stopped then
|
||||
on_done ()
|
||||
""
|
||||
end
|
||||
request.create(file)
|
||||
has_stopped := true
|
||||
""
|
||||
end
|
||||
request.dynamic(next)
|
||||
request.create(file)
|
||||
end
|
||||
# Instanciate the source
|
||||
source = request.dynamic(id=id,next)
|
||||
# Get its id.
|
||||
id = source.id(source)
|
||||
# The load function
|
||||
def load_playlist () =
|
||||
files =
|
||||
if test_process("test -d #{quote(!playlist_uri)}") then
|
||||
log(label=id,"playlist is a directory.")
|
||||
get_process_lines("find #{quote(!playlist_uri)} -type f | sort")
|
||||
else
|
||||
playlist = request.create.raw(!playlist_uri)
|
||||
result =
|
||||
if request.resolve(playlist) then
|
||||
playlist = request.filename(playlist)
|
||||
files = playlist.parse(playlist)
|
||||
list.map(snd,files)
|
||||
else
|
||||
log(label=id,"Couldn't read playlist: request resolution failed.")
|
||||
[]
|
||||
end
|
||||
request.destroy(playlist)
|
||||
result
|
||||
end
|
||||
if random then
|
||||
playlist := list.sort(fun (x,y) -> int_of_float(random.float()), files)
|
||||
else
|
||||
playlist := files
|
||||
end
|
||||
end
|
||||
if test_process("test -d #{quote(uri)}") then
|
||||
files = get_process_lines("find #{quote(uri)} -type f | sort")
|
||||
playlist.custom(files)
|
||||
else
|
||||
playlist = request.create.raw(uri)
|
||||
result =
|
||||
if request.resolve(playlist) then
|
||||
playlist = request.filename(playlist)
|
||||
files = playlist.parse(playlist)
|
||||
files = list.map(snd,files)
|
||||
playlist.custom(files)
|
||||
else
|
||||
log("Couldn't read playlist: request resolution failed.")
|
||||
fail ()
|
||||
end
|
||||
request.destroy(playlist)
|
||||
result
|
||||
# The reload function
|
||||
def reload(~uri="") =
|
||||
if uri != "" then
|
||||
playlist_uri := uri
|
||||
end
|
||||
log(label=id,"Reloading playlist with URI #{!playlist_uri}")
|
||||
has_stopped := false
|
||||
load_playlist()
|
||||
end
|
||||
# Load the playlist
|
||||
load_playlist()
|
||||
# Return
|
||||
(reload,source)
|
||||
end
|
||||
|
||||
# Custom playlist source written using the script language.
|
||||
# Will read directory or playlist, play all files and stop
|
||||
# @category Source / Input
|
||||
# @param ~id Force the value of the source ID.
|
||||
# @param ~random Randomize playlist content
|
||||
# @param ~on_done Function to execute when the playlist is finished
|
||||
# @param uri Playlist URI
|
||||
def playlist.once(~id="",~random=false,~on_done={()},uri)
|
||||
snd(playlist.reloadable(id=id,random=random,on_done=on_done,uri))
|
||||
end
|
||||
|
||||
# Mixes two streams, with faded transitions between the state when only the
|
||||
|
@ -588,7 +643,8 @@ def exec_at(~freq=1.,~pred,f)
|
|||
add_timeout(freq,check)
|
||||
end
|
||||
|
||||
# Register the replaygain protocol
|
||||
# Register the replaygain protocol.
|
||||
# @category Liquidsoap
|
||||
def replaygain_protocol(arg,delay)
|
||||
# The extraction program
|
||||
extract_replaygain = "#{configure.libdir}/extract-replaygain"
|
||||
|
|
|
@ -7,6 +7,7 @@ set("server.telnet", true)
|
|||
set("server.telnet.port", 1234)
|
||||
|
||||
queue = request.queue(id="queue", length=0.5)
|
||||
queue = cue_cut(queue)
|
||||
queue = audio_to_stereo(queue)
|
||||
|
||||
pypo_data = ref '0'
|
||||
|
|
|
@ -37,7 +37,6 @@ from configobj import ConfigObj
|
|||
# custom imports
|
||||
from util import *
|
||||
from api_clients import *
|
||||
from dls import *
|
||||
|
||||
# Set up command-line options
|
||||
parser = OptionParser()
|
||||
|
|
|
@ -12,6 +12,7 @@ import math
|
|||
from threading import Thread
|
||||
from subprocess import Popen, PIPE
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
# For RabbitMQ
|
||||
from kombu.connection import BrokerConnection
|
||||
|
@ -99,6 +100,7 @@ class PypoFetch(Thread):
|
|||
logger.error(" * See this page for more info (v1.7): http://wiki.sourcefabric.org/x/BQBF")
|
||||
logger.error(" * and also the 'FAQ and Support' page underneath it.")
|
||||
|
||||
"""
|
||||
def get_currently_scheduled(self, playlistsOrMedias, str_tnow_s):
|
||||
for key in playlistsOrMedias:
|
||||
start = playlistsOrMedias[key]['start']
|
||||
|
@ -114,9 +116,6 @@ class PypoFetch(Thread):
|
|||
|
||||
dtnow = datetime.today()
|
||||
tnow = dtnow.timetuple()
|
||||
|
||||
#timenow = time.time()
|
||||
#tnow = time.localtime(timenow) #tnow is struct_time. localtime is non-utc
|
||||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
|
||||
current_pkey = self.get_currently_scheduled(playlists, str_tnow_s)
|
||||
|
@ -135,6 +134,7 @@ class PypoFetch(Thread):
|
|||
|
||||
delta = dtnow - media_start #we get a TimeDelta object from this operation
|
||||
logger.info("Starting media item at %d second point", delta.seconds)
|
||||
"""
|
||||
|
||||
"""
|
||||
Process the schedule
|
||||
|
@ -148,9 +148,9 @@ class PypoFetch(Thread):
|
|||
logger = logging.getLogger('fetch')
|
||||
playlists = schedule_data["playlists"]
|
||||
|
||||
if bootstrapping:
|
||||
#if bootstrapping:
|
||||
#TODO: possible allow prepare_playlists to handle this.
|
||||
self.handle_shows_currently_scheduled(playlists)
|
||||
#self.handle_shows_currently_scheduled(playlists)
|
||||
|
||||
self.check_matching_timezones(schedule_data["server_timezone"])
|
||||
|
||||
|
@ -170,7 +170,7 @@ class PypoFetch(Thread):
|
|||
|
||||
# Download all the media and put playlists in liquidsoap "annotate" format
|
||||
try:
|
||||
liquidsoap_playlists = self.prepare_playlists(playlists)
|
||||
liquidsoap_playlists = self.prepare_playlists(playlists, bootstrapping)
|
||||
except Exception, e: logger.error("%s", e)
|
||||
|
||||
# Send the data to pypo-push
|
||||
|
@ -190,7 +190,7 @@ class PypoFetch(Thread):
|
|||
and stored in a playlist folder.
|
||||
file is e.g. 2010-06-23-15-00-00/17_cue_10.132-123.321.mp3
|
||||
"""
|
||||
def prepare_playlists(self, playlists):
|
||||
def prepare_playlists(self, playlists, bootstrapping):
|
||||
logger = logging.getLogger('fetch')
|
||||
|
||||
liquidsoap_playlists = dict()
|
||||
|
@ -211,18 +211,18 @@ class PypoFetch(Thread):
|
|||
try:
|
||||
os.mkdir(self.cache_dir + str(pkey))
|
||||
except Exception, e:
|
||||
pass
|
||||
logger.error(e)
|
||||
|
||||
#June 13, 2011: Commented this block out since we are not currently setting this to '1'
|
||||
#on the server side. Currently using a different method to detect if already played - Martin
|
||||
#if int(playlist['played']) == 1:
|
||||
# logger.info("playlist %s already played / sent to liquidsoap, so will ignore it", pkey)
|
||||
|
||||
ls_playlist = self.handle_media_file(playlist, pkey)
|
||||
ls_playlist = self.handle_media_file(playlist, pkey, bootstrapping)
|
||||
|
||||
liquidsoap_playlists[pkey] = ls_playlist
|
||||
except Exception, e:
|
||||
logger.info("%s", e)
|
||||
logger.error("%s", e)
|
||||
return liquidsoap_playlists
|
||||
|
||||
|
||||
|
@ -231,17 +231,43 @@ class PypoFetch(Thread):
|
|||
This handles both remote and local files.
|
||||
Returns an updated ls_playlist string.
|
||||
"""
|
||||
def handle_media_file(self, playlist, pkey):
|
||||
ls_playlist = []
|
||||
|
||||
def handle_media_file(self, playlist, pkey, bootstrapping):
|
||||
logger = logging.getLogger('fetch')
|
||||
for key in playlist['medias']:
|
||||
|
||||
ls_playlist = []
|
||||
|
||||
dtnow = datetime.today()
|
||||
str_tnow_s = dtnow.strftime('%Y-%m-%d-%H-%M-%S')
|
||||
|
||||
sortedKeys = sorted(playlist['medias'].iterkeys())
|
||||
|
||||
for key in sortedKeys:
|
||||
media = playlist['medias'][key]
|
||||
logger.debug("Processing track %s", media['uri'])
|
||||
|
||||
if bootstrapping:
|
||||
start = media['start']
|
||||
end = media['end']
|
||||
|
||||
if end <= str_tnow_s:
|
||||
continue
|
||||
elif start <= str_tnow_s and str_tnow_s < end:
|
||||
#song is currently playing and we just started pypo. Maybe there
|
||||
#was a power outage? Let's restart playback of this song.
|
||||
start_split = map(int, start.split('-'))
|
||||
media_start = datetime(start_split[0], start_split[1], start_split[2], start_split[3], start_split[4], start_split[5])
|
||||
logger.debug("Found media item that started at %s.", media_start)
|
||||
|
||||
delta = dtnow - media_start #we get a TimeDelta object from this operation
|
||||
logger.info("Starting media item at %d second point", delta.seconds)
|
||||
media['cue_in'] = delta.seconds + 10 #TODO is cue_in in seconds?
|
||||
td = timedelta(seconds=10)
|
||||
playlist['start'] = (dtnow + td).strftime('%Y-%m-%d-%H-%M-%S')
|
||||
logger.info("Crash detected, setting playlist to restart at %s", (dtnow + td).strftime('%Y-%m-%d-%H-%M-%S'))
|
||||
|
||||
|
||||
fileExt = os.path.splitext(media['uri'])[1]
|
||||
try:
|
||||
#logger.debug('No cue in/out detected for this file')
|
||||
dst = "%s%s/%s%s" % (self.cache_dir, str(pkey), str(media['id']), str(fileExt))
|
||||
|
||||
# download media file
|
||||
|
@ -256,9 +282,13 @@ class PypoFetch(Thread):
|
|||
|
||||
if fsize > 0:
|
||||
pl_entry = \
|
||||
'annotate:export_source="%s",media_id="%s",liq_start_next="%s",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s'\
|
||||
% (str(media['export_source']), media['id'], 0, str(float(media['fade_in']) / 1000), \
|
||||
str(float(media['fade_out']) / 1000), str(float(media['cue_in']) / 1000), str(float(media['cue_out']) / 1000), media['row_id'],dst)
|
||||
'annotate:export_source="%s",media_id="%s",liq_start_next="%s",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \
|
||||
% (str(media['export_source']), media['id'], 0, \
|
||||
str(float(media['fade_in']) / 1000), \
|
||||
str(float(media['fade_out']) / 1000), \
|
||||
str(float(media['cue_in'])), \
|
||||
str(float(media['cue_out'])), \
|
||||
media['row_id'], dst)
|
||||
|
||||
"""
|
||||
Tracks are only added to the playlist if they are accessible
|
||||
|
|
|
@ -97,9 +97,11 @@ class PypoPush(Thread):
|
|||
str_tnow_s = "%04d-%02d-%02d-%02d-%02d-%02d" % (tnow[0], tnow[1], tnow[2], tnow[3], tnow[4], tnow[5])
|
||||
|
||||
for pkey in schedule:
|
||||
plstart = pkey[0:19]
|
||||
plstart = schedule[pkey]['start'][0:19]
|
||||
#plstart = pkey[0:19]
|
||||
|
||||
playedFlag = (pkey in playedItems) and playedItems[pkey].get("played", 0)
|
||||
#playedFlag = (pkey in playedItems) and playedItems[pkey].get("played", 0)
|
||||
playedFlag = False
|
||||
|
||||
if plstart == str_tcoming_s or (plstart < str_tcoming_s and plstart > str_tcoming2_s and not playedFlag):
|
||||
logger.debug('Preparing to push playlist scheduled at: %s', pkey)
|
||||
|
|
Loading…
Reference in New Issue