4 from cStringIO import StringIO
10 from django.core.files.storage import default_storage
11 from django.core.urlresolvers import reverse
12 from django.contrib import messages
13 from django.http import HttpResponse, HttpResponseRedirect
14 from django.utils.translation import ugettext_lazy as _
15 from django.views.generic.base import RedirectView, TemplateView
16 from django.views.generic.dates import DayArchiveView
17 from django.views.generic.detail import DetailView
18 from django.views.generic.edit import FormView
19 from django.views.generic.list import ListView
21 from .forms import UploadTracksForm, NonstopZonesForm
22 from .models import SomaLogLine, Track, Artist, NonstopFile
23 from emissions.models import Nonstop
25 class SomaDayArchiveView(DayArchiveView):
26 queryset = SomaLogLine.objects.all()
27 date_field = "play_timestamp"
28 make_object_list = True
33 class SomaDayArchiveCsvView(SomaDayArchiveView):
34 def render_to_response(self, context, **response_kwargs):
36 writer = csv.writer(out)
37 for line in context['object_list']:
38 if line.filepath.track:
39 writer.writerow([line.play_timestamp.strftime('%Y-%m-%d %H:%M'),
40 line.filepath.short.encode('utf-8', 'replace'),
41 line.filepath.track.title.encode('utf-8', 'replace'),
42 line.filepath.track.artist.name.encode('utf-8', 'replace'),
43 line.filepath.track.language,
44 line.filepath.track.instru and 'instru' or '',
45 line.filepath.track.cfwb and 'cfwb' or ''])
47 writer.writerow([line.play_timestamp.strftime('%Y-%m-%d %H:%M'),
48 line.filepath.short.encode('utf-8', 'replace')])
49 return HttpResponse(out.getvalue(), content_type='text/csv; charset=utf-8')
52 class RedirectTodayView(RedirectView):
53 def get_redirect_url(self, *args, **kwargs):
54 today = datetime.datetime.today()
55 return reverse('archive_day', kwargs={
61 class TrackDetailView(DetailView):
64 def get_context_data(self, **kwargs):
65 ctx = super(TrackDetailView, self).get_context_data(**kwargs)
66 ctx['zones_form'] = NonstopZonesForm(instance=self.object)
69 def post(self, request, *args, **kwargs):
70 instance = self.get_object()
71 old_nonstop_zones = copy.copy(instance.nonstop_zones.all())
72 zones_form = NonstopZonesForm(request.POST, instance=instance)
74 new_nonstop_zones = self.get_object().nonstop_zones.all()
75 if set(old_nonstop_zones) != set(new_nonstop_zones):
76 instance.sync_nonstop_zones()
77 return HttpResponseRedirect('.')
80 class ArtistDetailView(DetailView):
84 class ArtistListView(ListView):
88 class ZoneStats(object):
89 def __init__(self, zone, from_date=None, until_date=None, **kwargs):
91 self.qs = Track.objects.filter(nonstop_zones=self.zone, **kwargs)
92 self.from_date = from_date
94 self.qs = self.qs.filter(nonstopfile__somalogline__play_timestamp__gte=from_date)
96 self.qs = self.qs.filter(nonstopfile__somalogline__play_timestamp__lte=until_date)
97 self.qs = self.qs.distinct()
99 def count(self, **kwargs):
100 return self.qs.filter(**kwargs).count()
102 def percentage(self, **kwargs):
106 return '%.2f%%' % (100. * self.count(**kwargs) / total)
109 return self.count(instru=True)
111 def instru_percentage(self):
112 return self.percentage(instru=True)
115 return self.count(sabam=True)
117 def sabam_percentage(self):
118 return self.percentage(sabam=True)
121 return self.count(cfwb=True)
123 def cfwb_percentage(self):
124 return self.percentage(cfwb=True)
127 return self.count(language='fr')
129 def french_percentage(self):
130 considered_tracks = self.count() - self.instru()
131 if considered_tracks == 0:
133 return '%.2f%%' % (100. * self.french() / considered_tracks)
136 return self.count(nonstopfile__creation_timestamp__gte=self.from_date)
138 def percent_new_files(self):
139 return self.percentage(nonstopfile__creation_timestamp__gte=self.from_date)
142 def parse_date(date):
143 if date.endswith('d'):
144 return datetime.datetime.today() + datetime.timedelta(int(date.rstrip('d')))
145 return datetime.datetime.strptime(date, '%Y-%m-%d').date()
147 class StatisticsView(TemplateView):
148 template_name = 'nonstop/statistics.html'
150 def get_context_data(self, **kwargs):
151 context = super(StatisticsView, self).get_context_data(**kwargs)
152 context['zones'] = Nonstop.objects.all().order_by('start')
154 if 'from' in self.request.GET:
155 kwargs['from_date'] = parse_date(self.request.GET['from'])
156 context['from_date'] = kwargs['from_date']
157 if 'until' in self.request.GET:
158 kwargs['until_date'] = parse_date(self.request.GET['until'])
159 if 'onair' in self.request.GET:
160 kwargs['nonstopfile__somalogline__on_air'] = True
161 for zone in context['zones']:
162 zone.stats = ZoneStats(zone, **kwargs)
166 class UploadTracksView(FormView):
167 form_class = UploadTracksForm
168 template_name = 'nonstop/upload.html'
171 def post(self, request, *args, **kwargs):
172 form_class = self.get_form_class()
173 form = self.get_form(form_class)
174 tracks = request.FILES.getlist('tracks')
175 if not form.is_valid():
176 return self.form_invalid(form)
177 missing_metadata = []
180 with tempfile.NamedTemporaryFile(prefix='track-upload') as tmpfile:
181 tmpfile.write(f.read())
183 metadata = mutagen.File(tmpfile.name, easy=True)
184 if not metadata or not metadata.get('artist') or not metadata.get('title'):
185 missing_metadata.append(f.name)
187 metadatas[f.name] = metadata
189 form.add_error('tracks', _('Missing metadata in: ') + ', '.join(missing_metadata))
190 return self.form_invalid(form)
193 metadata = metadatas[f.name]
194 artist_name = metadata.get('artist')[0]
195 track_title = metadata.get('title')[0]
197 monthdir = datetime.datetime.today().strftime('%Y-%m')
198 filepath = '%s/%s - %s - %s%s' % (monthdir,
199 datetime.datetime.today().strftime('%y%m%d'),
200 artist_name[:50].replace('/', ' ').strip(),
201 track_title[:80].replace('/', ' ').strip(),
202 os.path.splitext(f.name)[-1])
204 default_storage.save(os.path.join('nonstop', 'tracks', filepath), content=f)
206 nonstop_file = NonstopFile()
207 nonstop_file.set_track_filepath(filepath)
208 artist, created = Artist.objects.get_or_create(name=artist_name)
209 track, created = Track.objects.get_or_create(title=track_title, artist=artist)
210 nonstop_file.track = track
212 if request.POST.get('nonstop_zone'):
213 track.nonstop_zones.add(
214 Nonstop.objects.get(id=request.POST.get('nonstop_zone')))
216 messages.info(self.request, '%d new track(s)' % len(tracks))
217 return self.form_valid(form)