]> git.0d.be Git - django-panik-nonstop.git/blob - nonstop/utils.py
don't let soma loop short sounds
[django-panik-nonstop.git] / nonstop / utils.py
1 import datetime
2 import os
3 import shutil
4 import socket
5 import time
6
7 from django.template import loader
8 import xml.etree.ElementTree as ET
9
10 from .models import Track, SomaLogLine, StreamedDiffusion, Jingle, LOCAL_BASE_PATH
11
12
13 class SomaException(Exception):
14     pass
15
16
17 def get_current_nonstop_track():
18     try:
19         soma_log_line = SomaLogLine.objects.select_related().order_by('-play_timestamp')[0]
20     except IndexError:
21         # nothing yet
22         return {}
23     if soma_log_line.play_timestamp < (datetime.datetime.now() - datetime.timedelta(hours=1)):
24         # last known line is way too old
25         return {}
26     if not soma_log_line.on_air:
27         # nonstop should be on air but it's not :/
28         return {}
29     d = {}
30     current_nonstop_file = soma_log_line.filepath
31     if not 'Tranches/' in current_nonstop_file.filepath and (
32             not 'tracks/' in current_nonstop_file.filepath):
33         # nonstop is playing but it's not a nonstop track :/
34         return {}
35     current_track = soma_log_line.filepath.track
36     if current_track is None:
37         # nonstop is playing a nonstop track, but it's unknown :/
38         return {}
39     d = {'track_title': current_track.title}
40     if current_track.artist:
41         d['track_artist'] = current_track.artist.name
42     return d
43
44
45 def get_diffusion_file_path(diffusion):
46     return u'diffusions-auto/%s--%s' % (
47             diffusion.datetime.strftime('%Y%m%d-%H%M'),
48             diffusion.episode.emission.slug)
49
50 def is_already_in_soma(diffusion):
51     if StreamedDiffusion.objects.filter(diffusion=diffusion).count():
52         return True
53     return os.path.exists(os.path.join(LOCAL_BASE_PATH, get_diffusion_file_path(diffusion)))
54
55 class DuplicateDiffusionSlot(Exception):
56     pass
57
58 def add_diffusion(diffusion, **kwargs):
59     context = {}
60     streamed_diffusion = StreamedDiffusion.objects.filter(diffusion=diffusion).first()
61     if streamed_diffusion:
62         # program a stream
63         context['streamed_diffusion'] = streamed_diffusion
64         context['end'] = diffusion.end_datetime
65         context['jingle'] = streamed_diffusion.jingle
66     else:
67         # program a soundfile
68         soundfile = diffusion.episode.soundfile_set.filter(fragment=False)[0]
69         diffusion_path = get_diffusion_file_path(diffusion)
70
71         # copy file
72         if not os.path.exists(LOCAL_BASE_PATH):
73             raise SomaException('soma directory is not available')
74         if os.path.exists(os.path.join(LOCAL_BASE_PATH, diffusion_path)):
75             raise DuplicateDiffusionSlot()
76         os.mkdir(os.path.join(LOCAL_BASE_PATH, diffusion_path))
77         try:
78             shutil.copyfile(soundfile.file.path,
79                 os.path.join(LOCAL_BASE_PATH, diffusion_path, os.path.basename(soundfile.file.path)))
80         except IOError:
81             try:
82                 os.rmdir(os.path.join(LOCAL_BASE_PATH, diffusion_path))
83             except IOError:
84                 pass
85             raise SomaException('error copying file to soma')
86
87         context['diffusion_path'] = diffusion_path
88         # end should be a bit before the real end of file so the same file doesn't
89         # get repeated but shouldn't be less or equal than start date or soma would
90         # loop the file
91         context['end'] = diffusion.datetime + datetime.timedelta(seconds=
92                 max(((soundfile.duration or 300) - 180), 60))
93
94         if 'jingle_id' in kwargs:
95             context['jingle'] = Jingle.objects.get(id=kwargs['jingle_id'])
96
97     # create palinsesti
98     palinsesti_template = loader.get_template('nonstop/soma_palinsesti.xml')
99     context['episode'] = diffusion.episode
100     context['start'] = diffusion.datetime
101
102     palinsesti = palinsesti_template.render(context)
103     palinsesti_xml = ET.fromstring(palinsesti.encode('utf-8'))
104
105     # add to soma
106     def soma_connection():
107         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
108         s.connect(('soma', 12521))
109         s.recv(1024)  # -> b'soma 2.5 NO_SSL\n'
110         s.sendall(b'100 - Ok\n')
111         s.recv(1024)  # -> b'100 - Welcome to soma daemon\n'
112         s.sendall(b'\n')  # (empty password)
113         if s.recv(1024) != b'100 - Ok\n':
114             raise SomaException('failed to initialize soma connection')
115         return s
116
117     with soma_connection() as s:
118         s.sendall(b'109 - Get the current palinsesto\n')
119         palinsesto_bytes = b''
120         while True:
121             new_bytes = s.recv(200000)
122             if not new_bytes:
123                 break
124             palinsesto_bytes += new_bytes
125         if not palinsesto_bytes.startswith(b'100 - Ok\n'):
126             raise SomaException('failed to get palinsesto')
127         palinsesto_bytes = palinsesto_bytes[9:]
128
129     palinsesto_xml = ET.fromstring(palinsesto_bytes)
130     palinsesto_xml.append(palinsesti_xml)
131     with soma_connection() as s:
132         s.sendall(b'106 - Switch to a New Palinsesto Request\n')
133         if s.recv(1024) != b'100 - Ok\n':
134             raise SomaException('failed to switch palinsesto')
135         s.sendall(ET.tostring(palinsesto_xml))
136
137     # give it some time (...)
138     time.sleep(3)
139     with soma_connection() as s:
140         s.sendall(b'122 - Set the current Palinsesto as Default\n')
141         if s.recv(1024) != b'100 - Ok\n':
142             raise SomaException('failed to set current palinsesto as default')