use directories and allow filetypes other than FLAC
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Wed, 24 Aug 2011 09:13:40 +0000 (11:13 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Wed, 24 Aug 2011 09:13:40 +0000 (11:13 +0200)
apps/archive/forms.py
apps/archive/models.py
apps/archive/settings.py
apps/archive/tasks.py
apps/archive/templates/archive/file_managed.html
apps/archive/urls.py
apps/archive/utils.py
apps/archive/views.py

index c551cf8..cdc416e 100755 (executable)
@@ -7,7 +7,7 @@ from django.utils.translation import ugettext_lazy as _
 import mutagen
 
 from archive.models import Audiobook
-from archive.settings import FILES_PATH
+from archive.settings import FILES_PATH, NEW_PATH
 from archive.utils import ExistingFile, sha1_file
 
 class AudiobookForm(forms.ModelForm):
@@ -15,6 +15,10 @@ class AudiobookForm(forms.ModelForm):
         model = Audiobook
 
     def save(self, commit=True, path=None):
+        """ Performs normal save, with given file as an source audiobook.
+
+            `path' is relative to NEW_PATH.
+        """
         m = super(AudiobookForm, self).save(commit=False)
         m.modified = datetime.now()
 
@@ -24,9 +28,10 @@ class AudiobookForm(forms.ModelForm):
                 os.makedirs(FILES_PATH)
             # save the file in model
 
+            abs_path = os.path.join(NEW_PATH, path)
             m.source_file.save(
-                os.path.basename(path),
-                ExistingFile(path))
+                path,
+                ExistingFile(abs_path))
 
             f = open(m.source_file.path)
             m.source_sha1 = sha1_file(f)
index afa90b5..4d3f838 100644 (file)
@@ -1,10 +1,11 @@
 # -*- coding: utf-8 -*-
+import os.path
 
 from django.db import models
 from jsonfield.fields import JSONField
 from django.utils.translation import ugettext_lazy as _
 from archive.constants import status
-from archive.settings import FILES_PATH, ADVERT, LICENSE, ORGANIZATION, PROJECT
+from archive.settings import FILES_SAVE_PATH, ADVERT, LICENSE, ORGANIZATION, PROJECT
 from archive.utils import OverwriteStorage
 
 # Create your models here.
@@ -25,8 +26,12 @@ class Project(models.Model):
         return self.name
 
 
+def source_upload_to(intance, filename):
+    return os.path.join(FILES_SAVE_PATH, filename) # FIXME: what about really long file names?
+
+
 class Audiobook(models.Model):
-    source_file = models.FileField(upload_to='archive/files', max_length=255, 
+    source_file = models.FileField(upload_to=source_upload_to, max_length=255, 
             verbose_name=_('source file'), editable=False)
     source_sha1 = models.CharField(max_length=40, editable=False)
 
index 3c85f84..476f6c7 100755 (executable)
@@ -17,6 +17,9 @@ except AttributeError:
     FILES_PATH = os.path.abspath(os.path.join(settings.MEDIA_ROOT,
                         "archive/files"))
 
+if FILES_PATH.startswith(settings.MEDIA_ROOT):
+    FILES_SAVE_PATH = FILES_PATH[len(settings.MEDIA_ROOT):].lstrip('/')
+
 
 # here the app keeps the unmanaged (archive) files
 try:
index e8ce4fb..941bbc6 100755 (executable)
@@ -162,6 +162,7 @@ class Mp3Task(AudioFormatTask):
             '-ab', '64k',
             '-ac', '1',
             '-y',
+            '-acodec', 'libmp3lame',
             out_path
             ])
 
@@ -188,11 +189,12 @@ class OggTask(AudioFormatTask):
     @staticmethod
     def encode(in_path, out_path):
         # 44.1kHz 64kbps mono Ogg Vorbis
-        subprocess.check_call(['oggenc', 
-            in_path,
-            '--discard-comments',
-            '--resample', '44100',
-            '--downmix',
-            '-b', '64',
-            '-o', out_path
+        subprocess.check_call(['ffmpeg', 
+            '-i', in_path,
+            '-ar', '44100',
+            '-ab', '64k',
+            '-ac', '1',
+            '-y',
+            '-acodec', 'libvorbis',
+            out_path
             ])
index c67edea..92ee639 100755 (executable)
@@ -4,6 +4,10 @@
 
 {% block content %}
 
+<p>Plik źródłowy: <a href='{{ audiobook.source_file.url }}'>{{ path }}</a>
+(sha1: <tt>{{ audiobook.source_sha1 }}</tt>).
+</p>
+
 <h2>{% trans "Publishing" %}</h2>
 
 {% if audiobook.mp3_status or audiobook.ogg_status %}
index 40730ba..29552a2 100644 (file)
@@ -4,8 +4,8 @@ urlpatterns = patterns('',
     url(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'new/'}),
 
     url(r'^new/$', 'archive.views.list_new', name="list_new"),
-    url(r'^new/([^/]+)/$', 'archive.views.file_new', name="file_new"),
-    url(r'^move_to_archive/([^/]+)/$', 'archive.views.move_to_archive', name="move_to_archive"),
+    url(r'^new/(.+)/$', 'archive.views.file_new', name="file_new"),
+    url(r'^move_to_archive/(.+)/$', 'archive.views.move_to_archive', name="move_to_archive"),
 
     url(r'^unpublished/$', 'archive.views.list_unpublished', name="list_unpublished"),
     url(r'^publishing/$', 'archive.views.list_publishing', name="list_publishing"),
@@ -15,6 +15,6 @@ urlpatterns = patterns('',
     url(r'^cancel/(\d+)/$', 'archive.views.cancel_publishing', name="cancel_publishing"),
 
     url(r'^unmanaged/$', 'archive.views.list_unmanaged', name="list_unmanaged"),
-    url(r'^unmanaged/([^/]+)/$', 'archive.views.file_unmanaged', name="file_unmanaged"),
-    url(r'^move_to_new/([^/]+)/$', 'archive.views.move_to_new', name="move_to_new"),
+    url(r'^unmanaged/(.+)/$', 'archive.views.file_unmanaged', name="file_unmanaged"),
+    url(r'^move_to_new/(.+)/$', 'archive.views.move_to_new', name="move_to_new"),
 )
index c69fe1c..3e89a8b 100755 (executable)
@@ -1,4 +1,6 @@
 from hashlib import sha1
+import os
+import os.path
 from django.core.files.storage import FileSystemStorage
 from django.core.files.uploadedfile import UploadedFile
 
@@ -32,3 +34,11 @@ def sha1_file(f):
     for piece in iter(lambda: f.read(1024*1024), ''):
         sha.update(piece)
     return sha.hexdigest()
+
+
+def all_files(root_path):
+    root_len = len(root_path)
+    for path, dirs, files in os.walk(root_path):
+       for fname in files:
+           yield os.path.join(path, fname)[root_len:].lstrip('/')
+
index 8841dbb..cfed4a6 100644 (file)
@@ -19,6 +19,7 @@ from archive.constants import status
 from archive import models
 from archive.forms import AudiobookForm
 from archive import tasks
+from archive.utils import all_files
 
 
 @login_required
@@ -26,7 +27,7 @@ def list_new(request):
     division = 'new'
 
     path = settings.NEW_PATH
-    objects = sorted(os.listdir(path))
+    objects = sorted(all_files(path))
     return render(request, "archive/list_new.html", locals())
 
 
@@ -34,7 +35,8 @@ def list_new(request):
 def file_new(request, filename):
     division = 'new'
 
-    filepath = os.path.join(settings.NEW_PATH, filename.encode('utf-8'))
+    filepath = filename.encode('utf-8')
+    root_filepath = os.path.join(settings.NEW_PATH, filename.encode('utf-8'))
     if request.POST:
         form = AudiobookForm(request.POST)
         if form.is_valid():
@@ -45,21 +47,22 @@ def file_new(request, filename):
             return redirect(list_new)
 
     try:
-        tags = mutagen.File(filepath)
+        tags = mutagen.File(root_filepath)
     except IOError:
         raise Http404
     d = {}
-    for tag in tags:
-        value = tags[tag]
-        if isinstance(value, list):
-            d[tag] = value[0]
-        else:
-            d[tag] = value
-        if tag == 'project':
-            try:
-                d[tag] = models.Project.objects.get(name=d[tag]).pk
-            except models.Project.DoesNotExist:
-                d[tag] = None
+    if tags:
+        for tag in tags:
+            value = tags[tag]
+            if isinstance(value, list):
+                d[tag] = value[0]
+            else:
+                d[tag] = value
+            if tag == 'project':
+                try:
+                    d[tag] = models.Project.objects.get(name=d[tag]).pk
+                except models.Project.DoesNotExist:
+                    d[tag] = None
 
     if not request.POST:
         form = AudiobookForm(d)
@@ -73,9 +76,10 @@ def move_to_archive(request, filename):
 
     filename_str = filename.encode('utf-8')
     old_path = os.path.join(settings.NEW_PATH, filename_str)
-    if not os.path.isdir(settings.UNMANAGED_PATH):
-        os.makedirs(settings.UNMANAGED_PATH)
     new_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
+    new_dir = os.path.split(new_path)[0]
+    if not os.path.isdir(new_dir):
+        os.makedirs(new_dir)
 
     if not os.path.isfile(old_path):
         raise Http404
@@ -98,9 +102,10 @@ def move_to_new(request, filename):
 
     filename_str = filename.encode('utf-8')
     old_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
-    if not os.path.isdir(settings.NEW_PATH):
-        os.makedirs(settings.NEW_PATH)
     new_path = os.path.join(settings.NEW_PATH, filename_str)
+    new_dir = os.path.split(new_path)[0]
+    if not os.path.isdir(new_dir):
+        os.makedirs(new_dir)
 
     if not os.path.isfile(old_path):
         raise Http404
@@ -197,9 +202,12 @@ def file_managed(request, id):
                 raise Http404
 
     division = 'published' if audiobook.published() else 'unpublished'
+    path = audiobook.source_file.path[len(settings.FILES_PATH):].lstrip('/')
 
     # for tags update
     tags = mutagen.File(audiobook.source_file.path)
+    if not tags:
+        tags = {}
     form = AudiobookForm(instance=audiobook)
 
     return render(request, "archive/file_managed.html", locals())
@@ -209,7 +217,7 @@ def file_managed(request, id):
 def list_unmanaged(request):
     division = 'unmanaged'
 
-    objects = sorted(os.listdir(settings.UNMANAGED_PATH))
+    objects = sorted(all_files(settings.UNMANAGED_PATH))
     return render(request, "archive/list_unmanaged.html", locals())
 
 
@@ -218,6 +226,9 @@ def file_unmanaged(request, filename):
     division = 'unmanaged'
 
     tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename.encode('utf-8')))
+    if not tags:
+        tags = {}
+    
     err_exists = request.GET.get('exists')
     return render(request, "archive/file_unmanaged.html", locals())