]> git.0d.be Git - django-panik-nonstop.git/blob - nonstop/views.py
make it possible to edit track zones
[django-panik-nonstop.git] / nonstop / views.py
1 import copy
2 import csv
3 import datetime
4 from cStringIO import StringIO
5 import os
6 import tempfile
7
8 import mutagen
9
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
20
21 from .forms import UploadTracksForm, NonstopZonesForm
22 from .models import SomaLogLine, Track, Artist, NonstopFile
23 from emissions.models import Nonstop
24
25 class SomaDayArchiveView(DayArchiveView):
26     queryset = SomaLogLine.objects.all()
27     date_field = "play_timestamp"
28     make_object_list = True
29     allow_future = False
30     month_format = '%m'
31
32
33 class SomaDayArchiveCsvView(SomaDayArchiveView):
34     def render_to_response(self, context, **response_kwargs):
35         out = StringIO()
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 ''])
46             else:
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')
50
51
52 class RedirectTodayView(RedirectView):
53     def get_redirect_url(self, *args, **kwargs):
54         today = datetime.datetime.today()
55         return reverse('archive_day', kwargs={
56                         'year': today.year,
57                         'month': today.month,
58                         'day': today.day})
59
60
61 class TrackDetailView(DetailView):
62     model = Track
63
64     def get_context_data(self, **kwargs):
65         ctx = super(TrackDetailView, self).get_context_data(**kwargs)
66         ctx['zones_form'] = NonstopZonesForm(instance=self.object)
67         return ctx
68
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)
73         zones_form.save()
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('.')
78
79
80 class ArtistDetailView(DetailView):
81     model = Artist
82
83
84 class ArtistListView(ListView):
85     model = Artist
86
87
88 class ZoneStats(object):
89     def __init__(self, zone, from_date=None, until_date=None, **kwargs):
90         self.zone = zone
91         self.qs = Track.objects.filter(nonstop_zones=self.zone, **kwargs)
92         self.from_date = from_date
93         if from_date:
94             self.qs = self.qs.filter(nonstopfile__somalogline__play_timestamp__gte=from_date)
95         if until_date:
96             self.qs = self.qs.filter(nonstopfile__somalogline__play_timestamp__lte=until_date)
97         self.qs = self.qs.distinct()
98
99     def count(self, **kwargs):
100         return self.qs.filter(**kwargs).count()
101
102     def percentage(self, **kwargs):
103         total = self.count()
104         if total == 0:
105             return '-'
106         return '%.2f%%' % (100. * self.count(**kwargs) / total)
107
108     def instru(self):
109         return self.count(instru=True)
110
111     def instru_percentage(self):
112         return self.percentage(instru=True)
113
114     def sabam(self):
115         return self.count(sabam=True)
116
117     def sabam_percentage(self):
118         return self.percentage(sabam=True)
119
120     def cfwb(self):
121         return self.count(cfwb=True)
122
123     def cfwb_percentage(self):
124         return self.percentage(cfwb=True)
125
126     def french(self):
127         return self.count(language='fr')
128
129     def french_percentage(self):
130         considered_tracks = self.count() - self.instru()
131         if considered_tracks == 0:
132             return '-'
133         return '%.2f%%' % (100. * self.french() / considered_tracks)
134
135     def new_files(self):
136         return self.count(nonstopfile__creation_timestamp__gte=self.from_date)
137
138     def percent_new_files(self):
139         return self.percentage(nonstopfile__creation_timestamp__gte=self.from_date)
140
141
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()
146
147 class StatisticsView(TemplateView):
148     template_name = 'nonstop/statistics.html'
149
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')
153         kwargs = {}
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)
163         return context
164
165
166 class UploadTracksView(FormView):
167     form_class = UploadTracksForm
168     template_name = 'nonstop/upload.html'
169     success_url = '.'
170
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 = []
178         metadatas = {}
179         for f in tracks:
180             with tempfile.NamedTemporaryFile(prefix='track-upload') as tmpfile:
181                 tmpfile.write(f.read())
182                 f.seek(0)
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)
186             else:
187                 metadatas[f.name] = metadata
188         if missing_metadata:
189             form.add_error('tracks', _('Missing metadata in: ') + ', '.join(missing_metadata))
190             return self.form_invalid(form)
191
192         for f in tracks:
193             metadata = metadatas[f.name]
194             artist_name = metadata.get('artist')[0]
195             track_title = metadata.get('title')[0]
196
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])
203
204             default_storage.save(os.path.join('nonstop', 'tracks', filepath), content=f)
205
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
211             nonstop_file.save()
212             if request.POST.get('nonstop_zone'):
213                 track.nonstop_zones.add(
214                         Nonstop.objects.get(id=request.POST.get('nonstop_zone')))
215
216         messages.info(self.request, '%d new track(s)' % len(tracks))
217         return self.form_valid(form)