9 from django.conf import settings
10 from django.contrib import messages
11 from django.contrib.auth.forms import AuthenticationForm
12 from django.core.files.storage import default_storage
13 from django.db.models import Q
14 from django.http import HttpResponseForbidden, HttpResponseNotAllowed, HttpResponseRedirect, JsonResponse
15 from django.urls import reverse
16 from django.utils.translation import ugettext_lazy as _
17 from django.views.generic.base import TemplateView
18 from nonstop.models import SomaLogLine, Track
20 from emissions.models import Nonstop
21 from panikdb.context_processors import internal_ip
22 from panikdb.service_messages.models import Message
24 from .models import PigeEmailRequest
26 logger = logging.getLogger('panikdb')
29 def is_internal(request):
30 return internal_ip(request).get('internal_ip')
33 def is_regie_computer(request):
34 return internal_ip(request).get('current_ip') in settings.REGIE_IPS
37 class RegieHome(TemplateView):
38 template_name = 'regie-home.html'
40 def get_context_data(self, **kwargs):
41 context = super().get_context_data(**kwargs)
42 context['login_form'] = AuthenticationForm()
44 context['service_message'] = Message.objects.all().first()
46 if settings.PIGE_DOWNLOAD_BASE_URL:
47 context['has_pige'] = True
48 context['pige_minimum_date'] = datetime.datetime.now() - datetime.timedelta(days=100)
49 context['pige_hours'] = ['%02d' % x for x in range(24)]
50 context['pige_minutes'] = ['%02d' % x for x in range(0, 60, 15)]
52 if getattr(settings, 'NONSTOP_ON_AIR_SWITCH_URL', None) and getattr(self, 'request', None):
53 context['is_regie_computer'] = is_regie_computer(self.request)
54 context['has_switch'] = True
59 regie_home = RegieHome.as_view()
62 def pige_post(request, *args, **kwargs):
63 if request.method != 'POST':
64 return HttpResponseNotAllowed(['POST'])
65 # studio2-20160515-13h45-14h00m05.flac
66 name = '%(src)s-%(date)s-%(start_hour)sh%(start_min)s-%(end_hour)sh%(end_min)s' % {
67 'src': request.POST['src'],
68 'date': request.POST['date'].replace('-', ''),
69 'start_hour': request.POST['start_hour'],
70 'start_min': request.POST['start_min'],
71 'end_hour': request.POST['end_hour'],
72 'end_min': request.POST['end_min'],
74 if is_internal(request):
78 if 'sendmail' in request.POST:
79 email = request.POST['email']
80 PigeEmailRequest.objects.create(email=email, download_spec=name)
84 'An email with a download link will soon be sent to %s, '
85 'please be patient, it may take up to 20 minutes to arrive.'
89 return HttpResponseRedirect(reverse('regie-home'))
90 else: # direct download
91 return HttpResponseRedirect(settings.PIGE_DOWNLOAD_BASE_URL + '/' + name)
94 def json_tracks(tracks):
100 'title': track.title,
101 'artist': track.artist.name if track.artist_id else None,
102 'instru': track.instru,
103 'language': track.language,
104 'duration': '%d:%02d'
105 % (track.duration.total_seconds() / 60, track.duration.total_seconds() % 60),
113 def regie_tracks(request):
114 now = datetime.datetime.now()
116 for nonstop in Nonstop.objects.all():
117 if (nonstop.start < nonstop.end and (now.time() >= nonstop.start and now.time() < nonstop.end)) or (
118 nonstop.start > nonstop.end and (now.time() >= nonstop.start or now.time() < nonstop.end)
120 current_zone = nonstop
123 tracks = Track.objects.filter(duration__isnull=False)
124 tracks = tracks.filter(duration__gte=datetime.timedelta(minutes=2, seconds=30))
125 tracks = tracks.filter(duration__lt=datetime.timedelta(minutes=4, seconds=30))
127 tracks = tracks.filter(nonstop_zones__in=[current_zone.id])
128 tracks = tracks.exclude(language__isnull=True).exclude(language='')
129 tracks = tracks.order_by('?')
130 return json_tracks(tracks[:5])
133 def regie_tracks_search(request):
135 if q.startswith('https://'):
136 ytdl_path = default_storage.path('ytdl')
137 if not os.path.exists(ytdl_path):
139 for param in ('--dump-json', '--print-json'):
140 # make a first run with just metadata, this is to obtain the filename
141 # and use a file that was previously downloaded.
142 proc = subprocess.run(
150 ytdl_path + '/%(id)s.%(ext)s',
155 output = json.loads(proc.stdout)
156 filename = output['_filename']
157 # audio conversion may be done by youtube-dl and filename would still
158 # contain the original filename, look for files with same basename,
159 # regardeless of the extension.
160 base_filename = os.path.splitext(filename)[0]
162 real_filename = [x for x in glob.glob(base_filename + '*') if not x.endswith('.part')][0]
164 real_filename = filename
167 if not os.path.exists(real_filename):
168 return JsonResponse({'err': 1})
169 title = output['title']
170 duration = '%d:%02d' % (int(output['duration']) / 60, int(output['duration']) % 60)
171 url = os.path.join(settings.MEDIA_URL, 'ytdl', real_filename[len(ytdl_path) + 1 :])
172 good_filename = '%s%s' % (title, os.path.splitext(real_filename)[-1])
174 {'data': [{'title': title, 'duration': duration, 'url': url, 'filename': good_filename}]}
177 tracks = Track.objects.filter(duration__isnull=False).filter(
178 Q(title__icontains=q.lower()) | Q(artist__name__icontains=q.lower())
180 tracks = tracks.order_by('?')
181 return json_tracks(tracks[:5])
184 def playing(request):
185 latest_played = SomaLogLine.objects.select_related('track', 'track__artist').latest('play_timestamp')
186 duration = latest_played.track.duration
187 elapsed = datetime.datetime.now() - latest_played.play_timestamp
188 remaining = duration - elapsed
189 if remaining.total_seconds() < 2:
190 return JsonResponse({})
191 elif remaining.total_seconds() < 0:
192 remaining = datetime.timedelta(seconds=0)
194 if latest_played.track.artist:
195 response['artist'] = latest_played.track.artist.name
196 response['title'] = latest_played.track.title
197 response['duration'] = duration.seconds
198 response['elapsed'] = int(elapsed.total_seconds())
199 return JsonResponse(response)
202 def switch(request, *args, **kwargs):
203 if not is_regie_computer(request):
204 return HttpResponseForbidden()
205 logger.info('regie switch to %s', request.GET['selection'])
206 requests.post(settings.NONSTOP_ON_AIR_SWITCH_URL, data={'s': request.GET['selection']})
207 return JsonResponse({'err': 0})