import asyncio
import datetime
import json
+import logging
import random
import signal
import sys
from nonstop.app_settings import app_settings
+logger = logging.getLogger('stamina')
+
+
class Command(BaseCommand):
requires_system_checks = False
# last track overshot
# 1st strategy: remove last track and try to get a track with
# exact remaining time
- print('overshoot', current_datetime, file=sys.stderr)
+ logger.debug('Overshoot %s, %s', adjustment_counter, current_datetime)
playlist = playlist[:-1]
track = Track.objects.filter(
nonstop_zones=zone,
# or too many failures to get an appropriate file,
# allow whatever comes.
allow_overflow = True
- print('allow overflow', file=sys.stderr)
+ logger.debug('Allowing overflows')
current_datetime = start_datetime + sum(
[x.duration for x in playlist], datetime.timedelta(seconds=0))
- print('computed playlist: (computation time: %ss)' % (datetime.datetime.now() - t0), file=sys.stderr)
+ logger.info('Computed playlist: (computation time: %ss)',
+ (datetime.datetime.now() - t0))
current_datetime = start_datetime
for track in playlist:
- print(' ', current_datetime, track.duration, track.title, file=sys.stderr)
+ logger.debug('- track: %s %s %s', current_datetime, track.duration, track.title)
current_datetime += track.duration
- print(' ', current_datetime, '---', file=sys.stderr)
- print(' adjustment_counter:', adjustment_counter, file=sys.stderr)
-
+ logger.debug('- end: %s', current_datetime)
return playlist
def is_nonstop_on_air(self):
log_line.save()
async def player_process(self, item, timeout=None):
+ cmd = [app_settings.PLAYER_COMMAND] + app_settings.PLAYER_ARGS
+ if hasattr(item, 'is_stream') and item.is_stream():
+ cmd.append(item.stream.url)
+ logger.info('Play stream: %s', item.stream.url)
+ else:
+ cmd.append(item.file_path())
+ logger.info('Play file: %s', item.file_path())
if app_settings.DEBUG_WITH_SLEEPS:
+ # replace command by a sleep call, for silent debugging
if hasattr(item, 'is_stream') and item.is_stream():
cmd = 'sleep 86400 # %s' % item.stream.url
elif isinstance(item.duration, datetime.timedelta):
cmd = 'sleep %s # %s' % (item.duration.total_seconds(), item.file_path())
elif isinstance(item.duration, int):
cmd = 'sleep %s # %s' % (item.duration, item.file_path())
- else:
- cmd = [app_settings.PLAYER_COMMAND] + app_settings.PLAYER_ARGS
- if hasattr(item, 'is_stream') and item.is_stream():
- cmd.append(item.stream.url)
- else:
- cmd.append(item.file_path())
- print('cmd:', cmd, file=sys.stderr)
+ logger.debug('cmd %r', cmd)
if isinstance(cmd, str):
self.player = await asyncio.create_subprocess_shell(
cmd,
except IndexError:
break
self.current_track_start_datetime = now
- print(now, track.title, track.duration, file=sys.stderr)
+ logger.info('Track: %s (id: %s) (%s)', track.title, track.id, track.duration)
record_task = None
if isinstance(track, Track): # not jingles
record_task = asyncio.create_task(self.record_nonstop_line(track, datetime.datetime.now()))
break
self.playhead += 1
elif slot.is_stream():
- print(now, 'playing stream', slot.stream, file=sys.stderr)
+ logger.info('Stream: %s', slot.stream)
if slot.jingle_id:
await self.player_process(slot.jingle, timeout=60)
- print('timeout at', (slot.end_datetime - now).total_seconds(), file=sys.stderr)
+ logger.debug('Stream timeout: %s', (slot.end_datetime - now).total_seconds())
await self.player_process(slot, timeout=(slot.end_datetime - now).total_seconds())
else:
if hasattr(slot, 'episode'):
- print(now, 'playing sound', slot.episode, file=sys.stderr)
+ logger.info('Episode: %s (id: %s)', slot.episode, slot.episode.id)
else:
- print(now, 'playing random', file=sys.stderr)
+ logger.info('Random: %s', slot.episode, slot.episode.id)
if slot.jingle_id:
await self.player_process(slot.jingle, timeout=60)
await self.player_process(slot)
def recompute_playlist(self):
current_track = self.playlist[self.playhead]
- print('recompute_playlist, from', current_track.title, self.current_track_start_datetime + current_track.duration, 'to', self.slot.end_datetime, file=sys.stderr)
+ logger.debug('Recomputing playlist at %s, from %s to %s',
+ current_track.title,
+ self.current_track_start_datetime + current_track.duration,
+ self.slot.end_datetime)
playlist = self.get_playlist(self.slot,
self.current_track_start_datetime + current_track.duration, self.slot.end_datetime)
if playlist:
def recompute_slots(self):
now = datetime.datetime.now()
- # print(now, 'recompute_slots', file=sys.stderr)
diffusion = self.get_current_diffusion()
if diffusion:
self.slot = diffusion
async def recompute_slots_loop(self):
now = datetime.datetime.now()
- print(now, 'recompute_slots_loop', file=sys.stderr)
sleep = (60 - now.second) % 10 # adjust to awake at :00
while not self.quit:
await asyncio.sleep(sleep)
expected_slot = self.slot
if current_slot != expected_slot:
now = datetime.datetime.now()
- print(now, 'unexpected change', current_slot, 'vs', expected_slot, file=sys.stderr)
+ logger.info('Unexpected change, %s vs %s', current_slot, expected_slot)
if isinstance(current_slot, Nonstop) and isinstance(expected_slot, Nonstop):
# ask for a softstop, i.e. finish the track then switch.
self.softstop = True
elif isinstance(current_slot, Nonstop):
# interrupt nonstop
- print('interrupting nonstop', file=sys.stderr)
+ logger.info('Interrupting nonstop')
self.play_task.cancel()
elif current_slot.end_datetime > expected_slot.end_datetime:
now = datetime.datetime.now()
- print(now, 'change in end time, from %s to %s' %
- (current_slot.end_datetime, expected_slot.end_datetime), file=sys.stderr)
+ logger.debug('Change in end time, from %s to %s',
+ current_slot.end_datetime,
+ expected_slot.end_datetime)
if expected_slot.end_datetime - datetime.datetime.now() > datetime.timedelta(minutes=5):
# more than 5 minutes left, recompute playlist
self.recompute_playlist()
try:
message = data.decode().strip()
except UnicodeDecodeError:
- print('got invalid message %r' % message, file=sys.stderr)
+ logger.debug('Server, invalid message %r', message)
if not data:
end = True
continue
- print('got message: %r' % message, file=sys.stderr)
+ logger.debug('Server, message %r', message)
if message == 'status':
response = {'slot': str(self.slot)}
if isinstance(self.slot, Nonstop):
writer.close()
def sigterm_handler(self):
- print('got signal', file=sys.stderr)
+ logger.info('Got SIGTERM')
self.quit = True
self.play_task.cancel()
self.recompute_slots_task = asyncio.create_task(self.recompute_slots_loop())
while not self.quit:
duration = (self.slot.end_datetime - now).seconds
- print('next sure slot', duration, self.slot.end_datetime, file=sys.stderr)
+ logger.debug('Next sure shot %s (in %s)', self.slot.end_datetime, duration)
if duration < 2:
# next slot is very close, wait for it
await asyncio.sleep(duration)
await self.play_task
self.recompute_slots()
except asyncio.CancelledError as exc:
- print('exc:', exc, file=sys.stderr)
+ logger.exception('Main loop exception')
if self.player and self.player.returncode is None: # not finished
self.player.kill()
except KeyboardInterrupt: