d40f633e87b8c6ca02a372a10b5f89eda7931776
[audio.git] / apps / archive / views.py
1 # Create your views here.
2
3 from datetime import datetime
4 import os
5 import os.path
6 from urllib import quote
7
8 from archive import settings
9 from django.contrib.auth import logout
10 from django.contrib.auth.decorators import permission_required
11 from django.core.urlresolvers import reverse
12 from django.db.models import Q, Max
13 from django.http import Http404, HttpResponse
14 from django.shortcuts import render, redirect, get_object_or_404
15 from django.views.decorators.http import require_POST
16
17 import mutagen
18
19 from archive.constants import status
20 from archive import models
21 from archive.forms import AudiobookForm
22 from archive import tasks
23 from archive.utils import all_files
24
25
26 def list_new(request):
27     division = 'new'
28
29     path = settings.NEW_PATH
30     objects = sorted(all_files(path))
31     return render(request, "archive/list_new.html", locals())
32
33
34 @permission_required('archive.change_audiobook')
35 def file_new(request, filename):
36     division = 'new'
37
38     filepath = filename.encode('utf-8')
39     root_filepath = os.path.join(settings.NEW_PATH, filename.encode('utf-8'))
40     if request.POST:
41         form = AudiobookForm(request.POST)
42         if form.is_valid():
43             try:
44                 form.save(path=filepath)
45             except IOError:
46                 raise Http404
47             return redirect(list_new)
48
49     try:
50         tags = mutagen.File(root_filepath)
51     except IOError:
52         raise Http404
53     d = {}
54     if tags:
55         for tag in tags:
56             value = tags[tag]
57             if isinstance(value, list):
58                 d[tag] = value[0]
59             else:
60                 d[tag] = value
61             if tag == 'project':
62                 try:
63                     d[tag] = models.Project.objects.get(name=d[tag]).pk
64                 except models.Project.DoesNotExist:
65                     d[tag] = None
66
67     if not request.POST:
68         form = AudiobookForm(d)
69     return render(request, "archive/file_new.html", locals())
70
71
72 @require_POST
73 @permission_required('archive.change_audiobook')
74 def move_to_archive(request, filename):
75     """ move a new file to the unmanaged files dir """
76
77     filename_str = filename.encode('utf-8')
78     old_path = os.path.join(settings.NEW_PATH, filename_str)
79     new_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
80     new_dir = os.path.split(new_path)[0]
81     if not os.path.isdir(new_dir):
82         os.makedirs(new_dir)
83
84     if not os.path.isfile(old_path):
85         raise Http404
86
87     try:
88         os.link(old_path, new_path)
89         os.unlink(old_path)
90     except OSError:
91         # destination file exists, don't overwrite it
92         # TODO: this should probably be more informative
93         return redirect(file_new, filename)
94
95     return redirect(list_new)
96
97
98 @require_POST
99 @permission_required('archive.change_audiobook')
100 def remove_to_archive(request, aid):
101     """ move a managed file to the unmanaged files dir """
102
103     audiobook = get_object_or_404(models.Audiobook, id=aid)
104     old_path = audiobook.source_file.path
105     new_path = os.path.join(settings.UNMANAGED_PATH,
106         str(audiobook.source_file)[len(settings.FILES_SAVE_PATH):].lstrip('/'))
107     new_dir = os.path.split(new_path)[0]
108     if not os.path.isdir(new_dir):
109         os.makedirs(new_dir)
110
111     if not os.path.isfile(old_path):
112         raise Http404
113
114     try:
115         os.link(old_path, new_path)
116     except OSError:
117         # destination file exists, don't overwrite it
118         # TODO: this should probably be more informative
119         return redirect(file_new, filename)
120     else:
121         os.unlink(old_path)
122         audiobook.delete()
123
124     return redirect(list_unmanaged)
125
126 @require_POST
127 @permission_required('archive.change_audiobook')
128 def move_to_new(request, filename):
129     """ move a unmanaged file to new files dir """
130
131     filename_str = filename.encode('utf-8')
132     old_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
133     new_path = os.path.join(settings.NEW_PATH, filename_str)
134     new_dir = os.path.split(new_path)[0]
135     if not os.path.isdir(new_dir):
136         os.makedirs(new_dir)
137
138     if not os.path.isfile(old_path):
139         raise Http404
140
141     try:
142         os.link(old_path, new_path)
143         os.unlink(old_path)
144     except OSError:
145         # destination file exists, don't overwrite it
146         # TODO: this should probably be more informative
147         return redirect(reverse(file_unmanaged, args=[filename]) + "?exists=1")
148
149     return redirect(list_unmanaged)
150
151
152 @require_POST
153 @permission_required('archive.change_audiobook')
154 def publish(request, aid, publish=True):
155     """ mark file for publishing """
156     audiobook = get_object_or_404(models.Audiobook, id=aid)
157     tags = {
158         'name': audiobook.title,
159         'url': audiobook.url,
160         'tags': audiobook.new_publish_tags(),
161         }
162     audiobook.mp3_tags = tags
163     audiobook.ogg_tags = tags
164     audiobook.mp3_status = audiobook.ogg_status = status.WAITING
165     audiobook.save()
166     # isn't there a race here?
167     audiobook.mp3_task = tasks.Mp3Task.delay(aid, publish).task_id
168     audiobook.ogg_task = tasks.OggTask.delay(aid, publish).task_id
169     audiobook.save()
170
171     return redirect(file_managed, aid)
172
173
174 @require_POST
175 @permission_required('archive.change_audiobook')
176 def cancel_publishing(request, aid):
177     """ cancel scheduled publishing """
178     audiobook = get_object_or_404(models.Audiobook, id=aid)
179     # TODO: cancel tasks
180     audiobook.mp3_status = None
181     audiobook.ogg_status = None
182     audiobook.save()
183     return redirect(file_managed, aid)
184
185
186 def download(request, aid, which="source"):
187     if which not in ("source", "mp3", "ogg"):
188         raise Http404
189     audiobook = get_object_or_404(models.Audiobook, id=aid)
190     file_ = getattr(audiobook, "%s_file" % which)
191     if not file_:
192         raise Http404
193     ext = file_.path.rsplit('.', 1)[-1]
194     response = HttpResponse(mimetype='application/force-download')
195     
196     response['Content-Disposition'] = "attachment; filename*=UTF-8''%s.%s" % (
197         quote(audiobook.title.encode('utf-8'), safe=''), ext)
198     response['X-Sendfile'] = file_.path.encode('utf-8')
199     return response
200
201
202 def list_unpublished(request):
203     division = 'unpublished'
204
205     objects = models.Audiobook.objects.filter(Q(mp3_published=None) | Q(ogg_published=None))
206     return render(request, "archive/list_unpublished.html", locals())
207
208
209 def list_publishing(request):
210     division = 'publishing'
211
212     objects = models.Audiobook.objects.exclude(mp3_status=None, ogg_status=None)
213     objects_by_status = {}
214     for o in objects:
215         if o.mp3_status:
216             k = o.mp3_status, o.get_mp3_status_display()
217             objects_by_status.setdefault(k, []).append(o)
218         if o.ogg_status and o.ogg_status != o.mp3_status:
219             k = o.ogg_status, o.get_ogg_status_display()
220             objects_by_status.setdefault(k, []).append(o)
221     status_objects = sorted(objects_by_status.items(), reverse=True)
222
223     return render(request, "archive/list_publishing.html", locals())
224
225
226 def list_published(request):
227     division = 'published'
228
229     objects = models.Audiobook.objects.exclude(Q(mp3_published=None) | Q(ogg_published=None))
230     return render(request, "archive/list_published.html", locals())
231
232
233 @permission_required('archive.change_audiobook')
234 def file_managed(request, id):
235     audiobook = get_object_or_404(models.Audiobook, id=id)
236
237     if request.POST:
238         form = AudiobookForm(request.POST, instance=audiobook)
239         if form.is_valid():
240             try:
241                 form.save()
242             except IOError:
243                 raise Http404
244
245     division = 'published' if audiobook.published() else 'unpublished'
246     path = audiobook.source_file.path[len(settings.FILES_PATH):].lstrip('/')
247
248     # for tags update
249     tags = mutagen.File(audiobook.source_file.path)
250     if not tags:
251         tags = {}
252     form = AudiobookForm(instance=audiobook)
253
254     return render(request, "archive/file_managed.html", locals())
255
256
257 def list_unmanaged(request):
258     division = 'unmanaged'
259
260     objects = sorted(all_files(settings.UNMANAGED_PATH))
261     return render(request, "archive/list_unmanaged.html", locals())
262
263
264 def file_unmanaged(request, filename):
265     division = 'unmanaged'
266
267     tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename.encode('utf-8')))
268     if not tags:
269         tags = {}
270     
271     err_exists = request.GET.get('exists')
272     return render(request, "archive/file_unmanaged.html", locals())