7 from django.template import loader
8 from django.utils.timezone import now
9 import xml.etree.ElementTree as ET
11 from emissions.models import Diffusion, Schedule
12 from .models import SomaLogLine, ScheduledDiffusion, Jingle, RecurringStreamOccurence
13 from .app_settings import app_settings
16 class SomaException(Exception):
20 def get_current_nonstop_track():
22 soma_log_line = SomaLogLine.objects.select_related().order_by('-play_timestamp')[0]
26 if soma_log_line.play_timestamp < (datetime.datetime.now() - datetime.timedelta(hours=1)):
27 # last known line is way too old
29 if not soma_log_line.on_air:
30 # nonstop should be on air but it's not :/
33 current_nonstop_file = soma_log_line.filepath
34 if current_nonstop_file:
35 if 'Tranches/' not in current_nonstop_file.filepath and (
36 'tracks/' not in current_nonstop_file.filepath):
37 # nonstop is playing but it's not a nonstop track :/
39 current_track = soma_log_line.get_track()
40 if current_track is None:
41 # nonstop is playing a nonstop track, but it's unknown :/
43 d = {'track_title': current_track.title}
44 if current_track.artist:
45 d['track_artist'] = current_track.artist.name
49 def get_diffusion_file_path(diffusion):
50 return u'diffusions-auto/%s--%s' % (
51 diffusion.datetime.strftime('%Y%m%d-%H%M'),
52 diffusion.episode.emission.slug)
55 def is_already_in_soma(diffusion):
56 if isinstance(diffusion, Diffusion):
57 if ScheduledDiffusion.objects.filter(diffusion=diffusion).exists():
59 elif isinstance(diffusion, Schedule):
60 if RecurringStreamOccurence.objects.filter(diffusion__schedule=diffusion).exists():
65 def soma_connection():
66 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
67 s.connect(('soma', 12521))
68 s.recv(1024) # -> b'soma 2.5 NO_SSL\n'
69 s.sendall(b'100 - Ok\n')
70 s.recv(1024) # -> b'100 - Welcome to soma daemon\n'
71 s.sendall(b'\n') # (empty password)
72 if s.recv(1024) != b'100 - Ok\n':
73 raise SomaException('failed to initialize soma connection')
77 def add_soma_diffusion(diffusion):
79 context['diffusion'] = diffusion
80 context['jingle'] = diffusion.jingle
81 context['episode'] = diffusion.episode
82 context['start'] = diffusion.datetime
83 context['end'] = diffusion.end_datetime
85 if not diffusion.is_stream():
87 soundfile = diffusion.episode.soundfile_set.filter(fragment=False)[0]
88 diffusion_path = get_diffusion_file_path(diffusion)
91 if not os.path.exists(app_settings.LOCAL_BASE_PATH):
92 raise SomaException('soma directory is not available')
93 local_diffusion_path = os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path)
94 if os.path.exists(local_diffusion_path):
95 for filename in os.listdir(local_diffusion_path):
96 os.unlink(os.path.join(local_diffusion_path, filename))
98 os.mkdir(os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path))
100 shutil.copyfile(soundfile.file.path,
101 os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path, os.path.basename(soundfile.file.path)))
104 os.rmdir(os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path))
107 raise SomaException('error copying file to soma')
109 context['diffusion_path'] = diffusion_path
110 # end should be a bit before the real end of file so the same file doesn't
111 # get repeated but shouldn't be less or equal than start date or soma would
113 context['end'] = diffusion.datetime + datetime.timedelta(seconds=
114 max(((soundfile.duration or 480) - 180), 60))
117 palinsesti_template = loader.get_template('nonstop/soma_palinsesti.xml')
119 palinsesti = palinsesti_template.render(context)
120 palinsesti_xml = ET.fromstring(palinsesti.encode('utf-8'))
122 palinsesto_xml = get_palinsesto_xml()
123 palinsesto_xml.append(palinsesti_xml)
124 send_palinsesto_xml(palinsesto_xml)
125 diffusion.added_to_nonstop_timestamp = now()
129 def remove_soma_diffusion(diffusion):
130 palinsesto_xml = get_palinsesto_xml()
131 for palinsesto in palinsesto_xml.findall('Palinsesto'):
132 if palinsesto.findall('Description')[0].text.startswith(diffusion.soma_id):
133 palinsesto_xml.remove(palinsesto)
134 send_palinsesto_xml(palinsesto_xml)
137 def send_palinsesto_xml(palinsesto_xml):
138 with soma_connection() as s:
139 s.sendall(b'106 - Switch to a New Palinsesto Request\n')
140 if s.recv(1024) != b'100 - Ok\n':
141 raise SomaException('failed to switch palinsesto')
142 s.sendall(ET.tostring(palinsesto_xml))
144 # give it some time (...)
146 with soma_connection() as s:
147 s.sendall(b'122 - Set the current Palinsesto as Default\n')
148 if s.recv(1024) != b'100 - Ok\n':
149 raise SomaException('failed to set current palinsesto as default')
152 def get_palinsesto_xml():
153 with soma_connection() as s:
154 s.sendall(b'109 - Get the current palinsesto\n')
155 palinsesto_bytes = b''
157 new_bytes = s.recv(200000)
160 palinsesto_bytes += new_bytes
161 if not palinsesto_bytes.startswith(b'100 - Ok\n'):
162 raise SomaException('failed to get palinsesto')
163 palinsesto_bytes = palinsesto_bytes[9:]
164 palinsesto_xml = ET.fromstring(palinsesto_bytes)
165 return palinsesto_xml