]> git.0d.be Git - django-panik-nonstop.git/blob - nonstop/utils.py
f1abc27ef2dfab9afd67ab86fe8fd220200b9fab
[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 from django.utils.timezone import now
9 import xml.etree.ElementTree as ET
10
11 from emissions.models import Diffusion, Schedule
12 from .models import SomaLogLine, ScheduledDiffusion, Jingle, RecurringStreamOccurence
13 from .app_settings import app_settings
14
15
16 class SomaException(Exception):
17     pass
18
19
20 def get_current_nonstop_track():
21     try:
22         soma_log_line = SomaLogLine.objects.select_related().order_by('-play_timestamp')[0]
23     except IndexError:
24         # nothing yet
25         return {}
26     if soma_log_line.play_timestamp < (datetime.datetime.now() - datetime.timedelta(hours=1)):
27         # last known line is way too old
28         return {}
29     if not soma_log_line.on_air:
30         # nonstop should be on air but it's not :/
31         return {}
32     d = {}
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 :/
38             return {}
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 :/
42         return {}
43     d = {'track_title': current_track.title}
44     if current_track.artist:
45         d['track_artist'] = current_track.artist.name
46     return d
47
48
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)
53
54
55 def is_already_in_soma(diffusion):
56     if isinstance(diffusion, Diffusion):
57         if ScheduledDiffusion.objects.filter(diffusion=diffusion).exists():
58             return True
59     elif isinstance(diffusion, Schedule):
60         if RecurringStreamOccurence.objects.filter(diffusion__schedule=diffusion).exists():
61             return True
62     return False
63
64
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')
74     return s
75
76
77 def add_soma_diffusion(diffusion):
78     context = {}
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
84
85     if not diffusion.is_stream():
86         # program a soundfile
87         soundfile = diffusion.episode.soundfile_set.filter(fragment=False)[0]
88         diffusion_path = get_diffusion_file_path(diffusion)
89
90         # copy file
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))
97         else:
98             os.mkdir(os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path))
99         try:
100             shutil.copyfile(soundfile.file.path,
101                 os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path, os.path.basename(soundfile.file.path)))
102         except IOError:
103             try:
104                 os.rmdir(os.path.join(app_settings.LOCAL_BASE_PATH, diffusion_path))
105             except IOError:
106                 pass
107             raise SomaException('error copying file to soma')
108
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
112         # loop the file
113         context['end'] = diffusion.datetime + datetime.timedelta(seconds=
114                 max(((soundfile.duration or 480) - 180), 60))
115
116     # create palinsesti
117     palinsesti_template = loader.get_template('nonstop/soma_palinsesti.xml')
118
119     palinsesti = palinsesti_template.render(context)
120     palinsesti_xml = ET.fromstring(palinsesti.encode('utf-8'))
121
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()
126     diffusion.save()
127
128
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)
135
136
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))
143
144     # give it some time (...)
145     time.sleep(3)
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')
150
151
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''
156         while True:
157             new_bytes = s.recv(200000)
158             if not new_bytes:
159                 break
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