--- /dev/null
+*.pyc
+*.sqlite
+localsettings.py
--- /dev/null
+from archive.models import Project, Audiobook
+from django.contrib import admin
+
+admin.site.register(Project)
+admin.site.register(Audiobook)
--- /dev/null
+import os
+import os.path
+from datetime import datetime
+
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+import mutagen
+
+from archive.models import Audiobook
+from archive.settings import FILES_PATH
+from archive.utils import ExistingFile
+
+class AudiobookForm(forms.ModelForm):
+ class Meta:
+ model = Audiobook
+
+ def save(self, commit=True, path=None):
+ m = super(AudiobookForm, self).save(commit=False)
+ m.modified = datetime.now()
+
+ if path:
+ # adding a new audiobook
+ if not os.path.isdir(FILES_PATH):
+ os.makedirs(FILES_PATH)
+ # save the file in model
+ m.source_file.save(os.path.basename(path), ExistingFile(path))
+
+ if commit:
+ m.save()
+
--- /dev/null
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2011 Fundacja Nowoczesna Polska
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-05-17 12:35+0200\n"
+"PO-Revision-Date: 2011-05-17 12:37+0100\n"
+"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: models.py:15
+#: models.py:32
+msgid "project"
+msgstr "projekt"
+
+#: models.py:16
+msgid "projects"
+msgstr "projekty"
+
+#: models.py:24
+msgid "source file"
+msgstr "plik źródłowy"
+
+#: models.py:26
+msgid "title"
+msgstr "tytuł"
+
+#: models.py:27
+msgid "artist"
+msgstr "lektor"
+
+#: models.py:28
+msgid "arranger"
+msgstr "aranżer"
+
+#: models.py:29
+msgid "encoded by"
+msgstr "przyg. techn."
+
+#: models.py:30
+msgid "date"
+msgstr "data"
+
+#: models.py:33
+msgid "book url"
+msgstr "URL książki"
+
+#: models.py:46
+msgid "audiobook"
+msgstr "audiobook"
+
+#: models.py:47
+msgid "audiobooks"
+msgstr "audiobooki"
+
+#: templates/archive/base.html:7
+msgid "Audiobook repository"
+msgstr "Repozytorium audiobooków"
+
+#: templates/archive/base.html:12
+msgid "New"
+msgstr "Nowe"
+
+#: templates/archive/base.html:13
+msgid "Unpublished"
+msgstr "Nie opublikowane"
+
+#: templates/archive/base.html:14
+msgid "Published"
+msgstr "Opublikowane"
+
+#: templates/archive/base.html:15
+msgid "Archive"
+msgstr "Archiwum"
+
+#: templates/archive/file_managed.html:6
+msgid "Publishing"
+msgstr "Publikacja"
+
+#: templates/archive/file_managed.html:9
+msgid "Audiobook marked for publishing with tags:"
+msgstr "Audiobook zaznaczony do publikacji z tagami:"
+
+#: templates/archive/file_managed.html:18
+msgid "Publishing already in progress."
+msgstr "Publikowanie rozpoczęte."
+
+#: templates/archive/file_managed.html:22
+msgid "Cancel publishing"
+msgstr "Anuluj publikację"
+
+#: templates/archive/file_managed.html:37
+msgid "Publish"
+msgstr "Opublikuj"
+
+#: templates/archive/file_managed.html:50
+msgid "Update tags"
+msgstr "Uaktualnij tagi"
+
+#: templates/archive/file_managed.html:69
+#: templates/archive/file_new.html:19
+msgid "Commit"
+msgstr "Zatwierdź"
+
+#: templates/archive/file_new.html:8
+msgid "Move to archive"
+msgstr "Przenieś do archiwum"
+
+#: templates/archive/file_unmanaged.html:6
+msgid "File with same name already exists!"
+msgstr "Plik o tej nazwie już istnieje!"
+
+#: templates/archive/file_unmanaged.html:28
+msgid "Move to new files"
+msgstr "Przenieś do nowych plików"
+
+#: templates/archive/list_new.html:6
+msgid "New audiobooks"
+msgstr "Nowe audiobooki"
+
+#: templates/archive/list_new.html:11
+msgid "Put source audiobooks in:"
+msgstr "Umieść nowe audiobooki w:"
+
+#: templates/archive/list_published.html:6
+msgid "Published audiobooks"
+msgstr "Opublikowane audiobooki"
+
+#: templates/archive/list_unmanaged.html:5
+msgid "Unmanaged archive"
+msgstr "Audiobooki archiwalne"
+
+#: templates/archive/list_unpublished.html:6
+msgid "Unpublished audiobooks"
+msgstr "Nie opublikowane audiobooki"
+
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Project'
+ db.create_table('archive_project', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128, db_index=True)),
+ ('sponsors', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('archive', ['Project'])
+
+ # Adding model 'Audiobook'
+ db.create_table('archive_audiobook', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('source_file', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('artist', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('conductor', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('encoded_by', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('date', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['archive.Project'])),
+ ('url', self.gf('django.db.models.fields.URLField')(max_length=255)),
+ ('modified', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+ ('published_tags', self.gf('jsonfield.fields.JSONField')(null=True)),
+ ('mp3_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True)),
+ ('ogg_file', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True)),
+ ('publishing_tags', self.gf('jsonfield.fields.JSONField')(null=True)),
+ ('publish_wait', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+ ('publishing', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('published', self.gf('django.db.models.fields.DateTimeField')(null=True)),
+ ))
+ db.send_create_signal('archive', ['Audiobook'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Project'
+ db.delete_table('archive_project')
+
+ # Deleting model 'Audiobook'
+ db.delete_table('archive_audiobook')
+
+
+ models = {
+ 'archive.audiobook': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'Audiobook'},
+ 'artist': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'conductor': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'date': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'encoded_by': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'mp3_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True'}),
+ 'ogg_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True'}),
+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['archive.Project']"}),
+ 'publish_wait': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'published': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'published_tags': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
+ 'publishing': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'publishing_tags': ('jsonfield.fields.JSONField', [], {'null': 'True'}),
+ 'source_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '255'})
+ },
+ 'archive.project': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'Project'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128', 'db_index': 'True'}),
+ 'sponsors': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['archive']
--- /dev/null
+from django.db import models
+from jsonfield.fields import JSONField
+from django.utils.translation import ugettext_lazy as _
+
+# Create your models here.
+
+
+class Project(models.Model):
+ """ an audiobook project, needed for specyfing sponsors """
+
+ name = models.CharField(max_length=128, unique=True, db_index=True, verbose_name="Nazwa")
+ sponsors = models.TextField(blank=True, null=True, verbose_name="Sponsorzy")
+
+ class Meta:
+ verbose_name = _("project")
+ verbose_name_plural = _("projects")
+ ordering = ("name",)
+
+ def __unicode__(self):
+ return self.name
+
+
+class Audiobook(models.Model):
+ source_file = models.FileField(upload_to='archive/files', verbose_name=_('source file'), editable=False)
+
+ title = models.CharField(max_length=255, verbose_name=_('title'))
+ artist = models.CharField(max_length=255, verbose_name=_('artist'))
+ conductor = models.CharField(max_length=255, verbose_name=_('conductor'))
+ encoded_by = models.CharField(max_length=255, verbose_name=_('encoded by'))
+ date = models.CharField(max_length=255, verbose_name=_('date'))
+ project = models.ForeignKey(Project, verbose_name=_('project'))
+ url = models.URLField(max_length=255, verbose_name=_('book url'))
+ modified = models.DateTimeField(null=True, editable=False)
+
+ published_tags = JSONField(null=True, editable=False)
+ mp3_file = models.FileField(null=True, upload_to='archive/final', editable=False)
+ ogg_file = models.FileField(null=True, upload_to='archive/final', editable=False)
+ publishing_tags = JSONField(null=True, editable=False)
+
+ publish_wait = models.DateTimeField(null=True, editable=False) # somebody hit "publish"
+ publishing = models.BooleanField(default=False, editable=False)
+ published = models.DateTimeField(null=True, editable=False)
+
+ class Meta:
+ verbose_name = _("audiobook")
+ verbose_name_plural = _("audiobooks")
+ ordering = ("title",)
+
+ def __unicode__(self):
+ return self.title
+
+ def new_publish_tags(self):
+ return {
+ 'title': self.title,
+ 'copyright': 'Fundacja Nowoczesna Polska',
+ }
--- /dev/null
+import os.path
+from django.conf import settings
+
+# this is where the end user puts new files
+try:
+ NEW_PATH = settings.ARCHIVE_NEW_PATH
+except AttributeError:
+ NEW_FILES_PATH = os.path.abspath(os.path.join(settings.MEDIA_ROOT,
+ "archive/new"))
+
+# here the application keeps its managed files
+try:
+ FILES_PATH = settings.ARCHIVE_FILES_PATH
+except AttributeError:
+ FILES_PATH = os.path.abspath(os.path.join(settings.MEDIA_ROOT,
+ "archive/files"))
+
+
+# here the app keeps the unmanaged (archive) files
+try:
+ UNMANAGED_PATH = settings.ARCHIVE_UNMANAGED_PATH
+except AttributeError:
+ UNMANAGED_PATH = os.path.abspath(os.path.join(settings.MEDIA_ROOT,
+ "archive/unmanaged"))
+
+
+# here the app keeps the resulting (published) files
+try:
+ FINAL_PATH = settings.ARCHIVE_FINAL_PATH
+except AttributeError:
+ FINAL_PATH = os.path.abspath(os.path.join(settings.MEDIA_ROOT,
+ "archive/final"))
--- /dev/null
+body {
+ margin: 0;
+ font-family: verdana, sans-serif;
+ font-size: 12px;
+}
+
+a {
+ color: #bf6000;
+ text-decoration: none;
+}
+
+.clr {
+ clear: both;
+}
+
+
+#repo-zones-nav {
+ padding: 5px 5px 0 10px;
+ background: #ffdfbf;
+ border-bottom: 1px solid #ff8000;
+}
+
+#repo-zones-nav a {
+ display: block;
+ float: left;
+ padding: 5px 20px 5px 20px;
+ margin-bottom: -1px;
+ border-width: 1px;
+ border-style: solid;
+ border-color: rgba(0,0,0,0);
+}
+
+#repo-zones-nav .active {
+ background: white;
+ border-color: #ff8000 #ff8000 white #ff8000;
+}
+
+#content {
+ padding: 10px;
+}
+
+
+.errorlist {
+ margin: 0;
+}
+
+.errorlist li {
+ color: red;
+}
--- /dev/null
+{% load i18n %}
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}style.css" />
+ <title>{% trans "Audiobook repository" %}</title>
+</head>
+<body>
+
+<div id="repo-zones-nav">
+ <a {% if division = "new" %}class="active" {% endif %}href="{% url list_new %}">{% trans "New" %}</a>
+ <a {% if division = "unpublished" %}class="active" {% endif %}href="{% url list_unpublished %}">{% trans "Unpublished" %}</a>
+ <a {% if division = "published" %}class="active" {% endif %}href="{% url list_published %}">{% trans "Published" %}</a>
+ <a {% if division = "unmanaged" %}class="active" {% endif %}href="{% url list_unmanaged %}">{% trans "Archive" %}</a>
+ <div class='clr' ></div>
+</div>
+
+<div id="messages">
+{% block messages %}{% endblock %}
+</div>
+
+<div id="content">
+{% block content %}{% endblock %}
+</div>
+
+</body>
+</html>
--- /dev/null
+{% extends "archive/base.html" %}
+{% load i18n %}
+
+{% block content %}
+
+<h2>{% trans "Publishing" %}</h2>
+
+{% if audiobook.publish_wait %}
+ <p>{% trans "Audiobook marked for publishing with tags:" %}</p>
+
+ <table>
+ {% for t, v in audiobook.publishing_tags.items %}
+ <tr><th>{{ t }}</th><td>{{ v }}</td></tr>
+ {% endfor %}
+ </table>
+
+ {% if audiobook.publishing %}
+ <p>{% trans "Publishing already in progress." %}</p>
+ {% else %}
+ <form method="post" action="{% url cancel_publishing audiobook.id %}">
+ {% csrf_token %}
+ <input type="submit" value="{% trans "Cancel publishing" %}" />
+ </form>
+ {% endif %}
+{% else %}
+ {% if audiobook.published %}
+ Here be currently published version, for comparison.
+ {% endif %}
+
+ <form method="post" action="{% url publish audiobook.id %}">
+ <table>
+ {% for k, v in audiobook.new_publish_tags.items %}
+ <tr><th>{{ k }}</th><td>{{ v }}</td></tr>
+ {% endfor %}
+
+ {% csrf_token %}
+ <tr><th></th><td><input type="submit" value="{% trans "Publish" %}" /></td></tr>
+ </table>
+ </form>
+{% endif %}
+
+
+
+
+<hr />
+
+
+
+
+<h2>{% trans "Update tags" %}</h2>
+
+
+<table class="file_tags">
+ {% for t, v in tags.items %}
+ <tr><th>{{t}}</th><td>
+ {% for x in v %}
+ {{x}}<br />
+ {% endfor %}
+ </td></tr>
+ {% endfor %}
+</table>
+
+
+
+<form method='post' action='.'>
+ {% csrf_token %}
+ <table>
+ {{ form.as_table }}
+ <td></td><td><input type="submit" value='{% trans "Commit" %}' /></td></td>
+ </table>
+</form>
+
+
+
+
+{% endblock %}
--- /dev/null
+{% extends "archive/base.html" %}
+{% load i18n tags %}
+
+{% block content %}
+
+<form method="post" action="{% url move_to_archive filename %}">
+ {% csrf_token %}
+ <input type="submit" value="{% trans "Move to archive" %}" />
+</form>
+
+
+{% multiple_tags_table tags %}
+
+
+<form method='post' action='.'>
+ {% csrf_token %}
+ <table>
+ {{ form.as_table }}
+ <td></td><td><input type="submit" value='{% trans "Commit" %}' /></td></td>
+ </table>
+</form>
+
+{% endblock %}
--- /dev/null
+{% extends "archive/base.html" %}
+{% load i18n %}
+
+{% block messages %}
+ {% if err_exists %}
+ <p>{% trans "File with same name already exists!" %}</p>
+ {% endif %}
+{% endblock %}
+
+
+{% block content %}
+
+
+<ul id="tags">
+ {% for t, v in tags.items %}
+ <li>{{t}}
+ <ul>
+ {% for x in v %}
+ <li>{{x}}</li>
+ {% endfor %}
+ </ul></li>
+ {% endfor %}
+</ul>
+
+
+<form method="post" action="{% url move_to_new filename %}">
+ {% csrf_token %}
+ <input type="submit" value="{% trans "Move to new files" %}" />
+</form>
+
+{% endblock %}
--- /dev/null
+{% extends "archive/base.html" %}
+{% load i18n %}
+
+
+{% block content %}
+
+ <div id="file-list">
+ <h1>{% block file-list-title %}{% endblock %}</h1>
+ <div>{% block file-list-info %}{% endblock %}</div>
+ <ul>{% block file-list %}{% endblock %}</ul>
+ </div>
+
+{% endblock %}
--- /dev/null
+{% extends "archive/list.html" %}
+{% load i18n %}
+
+
+{% block file-list-title %}
+ {% trans "New audiobooks" %}
+{% endblock %}
+
+
+{% block file-list-info %}
+ {% trans "Put source audiobooks in:" %}
+ <span>{{ path }}</span>
+{% endblock %}
+
+
+{% block file-list %}
+ {% for file in objects %}
+ <li>
+ <a href='{% url file_new file %}'>{{ file }}</a>
+ </li>
+ {% endfor %}
+{% endblock %}
--- /dev/null
+{% extends "archive/list.html" %}
+{% load i18n %}
+
+
+{% block file-list-title %}
+ {% trans "Published audiobooks" %}
+{% endblock %}
+
+
+{% block file-list-info %}
+{% endblock %}
+
+
+{% block file-list %}
+ {% for file in objects %}
+ <li>
+ <a href='{% url file file %}'>{{ file }}</a></form>
+ </li>
+ {% endfor %}
+{% endblock %}
--- /dev/null
+{% extends "archive/list.html" %}
+{% load i18n %}
+
+{% block file-list-title %}
+ {% trans "Unmanaged archive" %}
+{% endblock %}
+
+
+{% block file-list-info %}
+{% endblock %}
+
+
+{% block file-list %}
+ {% for file in objects %}
+ <li>
+ <a href='{% url file_unmanaged file %}'>{{ file }}</a>
+ </li>
+ {% endfor %}
+{% endblock %}
--- /dev/null
+{% extends "archive/list.html" %}
+{% load i18n %}
+
+
+{% block file-list-title %}
+ {% trans "Unpublished audiobooks" %}
+{% endblock %}
+
+
+{% block file-list-info %}
+{% endblock %}
+
+
+{% block file-list %}
+ {% for file in objects %}
+ <li>
+ <a href='{% url file file.id %}'>{{ file }}</a></form>
+ </li>
+ {% endfor %}
+{% endblock %}
--- /dev/null
+<table>
+ {% for t, v in tags.items %}
+ <tr><th>{{t}}</th><td>
+ {% for x in v %}
+ <div>{{x}}</div>
+ {% endfor %}
+ </td></tr>
+ {% endfor %}
+</table>
--- /dev/null
+from django import template
+
+register = template.Library()
+
+@register.simple_tag
+def multiple_tags_table(tags):
+ return template.loader.render_to_string(
+ "archive/tags/multiple_tags_table.html",
+ {"tags": tags}
+ )
+
+
+#@register.simple_tag
+#def multiple_tags_table(tags):
+# return template.loader.render_to_string(
+# "archive/tags/multiple_tags_table.html",
+# {"tags": tags}
+# )
+
--- /dev/null
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
--- /dev/null
+from django.conf.urls.defaults import patterns, include, url
+
+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'^unpublished/$', 'archive.views.list_unpublished', name="list_unpublished"),
+ url(r'^published/$', 'archive.views.list_published', name="list_published"),
+ url(r'^file/(\d+)/$', 'archive.views.file_managed', name="file"),
+ url(r'^publish/(\d+)/$', 'archive.views.publish', name="publish"),
+ 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"),
+)
--- /dev/null
+from django.core.files.uploadedfile import UploadedFile
+
+class ExistingFile(UploadedFile):
+
+ def __init__(self, path, *args, **kwargs):
+ self.path = path
+ return super(ExistingFile, self).__init__(*args, **kwargs)
+
+ def temporary_file_path(self):
+ return self.path
+
+ def close(self):
+ pass
--- /dev/null
+# Create your views here.
+
+from datetime import datetime
+import os
+import os.path
+
+from archive import settings
+from django.core.urlresolvers import reverse
+from django.http import Http404
+from django.shortcuts import render, redirect, get_object_or_404
+from django.views.decorators.http import require_POST
+
+import mutagen
+
+from archive import models
+from archive.forms import AudiobookForm
+
+
+def list_new(request):
+ division = 'new'
+
+ path = settings.NEW_PATH
+ objects = sorted(os.listdir(path))
+ return render(request, "archive/list_new.html", locals())
+
+
+def file_new(request, filename):
+ division = 'new'
+
+ filepath = os.path.join(settings.NEW_PATH, filename)
+ if request.POST:
+ form = AudiobookForm(request.POST)
+ if form.is_valid():
+ try:
+ form.save(path=filepath)
+ except IOError:
+ raise Http404
+ return redirect(list_new)
+
+ try:
+ tags = mutagen.File(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
+ print d
+
+ if not request.POST:
+ form = AudiobookForm(d)
+ return render(request, "archive/file_new.html", locals())
+
+
+@require_POST
+def move_to_archive(request, filename):
+ """ move a new file to the unmanaged files dir """
+
+ old_path = os.path.join(settings.NEW_PATH, filename)
+ if not os.path.isdir(settings.UNMANAGED_PATH):
+ os.makedirs(settings.UNMANAGED_PATH)
+ new_path = os.path.join(settings.UNMANAGED_PATH, filename)
+
+ if not os.path.isfile(old_path):
+ raise Http404
+
+ try:
+ os.link(old_path, new_path)
+ os.unlink(old_path)
+ except OSError:
+ # destination file exists, don't overwrite it
+ # TODO: this should probably be more informative
+ return redirect(file_new, filename)
+
+ return redirect(list_new)
+
+
+@require_POST
+def move_to_new(request, filename):
+ """ move a unmanaged file to new files dir """
+
+ old_path = os.path.join(settings.UNMANAGED_PATH, filename)
+ if not os.path.isdir(settings.NEW_PATH):
+ os.makedirs(settings.NEW_PATH)
+ new_path = os.path.join(settings.NEW_PATH, filename)
+
+ if not os.path.isfile(old_path):
+ raise Http404
+
+ try:
+ os.link(old_path, new_path)
+ os.unlink(old_path)
+ except OSError:
+ # destination file exists, don't overwrite it
+ # TODO: this should probably be more informative
+ return redirect(reverse(file_unmanaged, args=[filename]) + "?exists=1")
+
+ return redirect(list_unmanaged)
+
+@require_POST
+def publish(request, id):
+ """ mark file for publishing """
+ audiobook = get_object_or_404(models.Audiobook, id=id)
+ audiobook.publish_wait = datetime.now()
+ audiobook.publishing_tags = audiobook.new_publish_tags()
+ audiobook.save()
+ return redirect(file_managed, id)
+
+@require_POST
+def cancel_publishing(request, id):
+ """ cancel scheduled publishing """
+ audiobook = get_object_or_404(models.Audiobook, id=id)
+ if not audiobook.publishing:
+ audiobook.publish_wait = None
+ audiobook.publishing_tags = None
+ audiobook.save()
+ return redirect(file_managed, id)
+
+
+def list_unpublished(request):
+ division = 'unpublished'
+
+ objects = models.Audiobook.objects.filter(published=None)
+ return render(request, "archive/list_unpublished.html", locals())
+
+
+
+def file_managed(request, id):
+ audiobook = get_object_or_404(models.Audiobook, id=id)
+ division = 'published' if audiobook.published else 'unpublished'
+
+ # for tags update
+ tags = mutagen.File(audiobook.source_file.path)
+ form = AudiobookForm(instance=audiobook)
+
+ return render(request, "archive/file_managed.html", locals())
+
+
+
+def list_published(request):
+ division = 'published'
+
+ objects = models.Audiobook.objects.exclude(published=None)
+ return render(request, "archive/list_published.html", locals())
+
+
+
+
+def list_unmanaged(request):
+ division = 'unmanaged'
+
+ objects = sorted(os.listdir(settings.UNMANAGED_PATH))
+ return render(request, "archive/list_unmanaged.html", locals())
+
+
+def file_unmanaged(request, filename):
+ division = 'unmanaged'
+
+ tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename))
+ err_exists = request.GET.get('exists')
+ return render(request, "archive/file_unmanaged.html", locals())
+
--- /dev/null
+#!/usr/bin/env python
+from django.core.management import execute_manager
+import imp
+try:
+ imp.find_module('settings') # Assumed to be in the same directory.
+except ImportError:
+ import sys
+ sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
+ sys.exit(1)
+
+import settings
+
+if __name__ == "__main__":
+ execute_manager(settings)
--- /dev/null
+# Django settings for audiobooks project.
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, os.path.join(PROJECT_ROOT, "../apps"))
+
+
+
+DEBUG = False
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ # ('Your Name', 'your_email@example.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': os.path.join(PROJECT_ROOT, 'dev.sqlite'), # Or path to database file if using sqlite3.
+ 'USER': '', # Not used with sqlite3.
+ 'PASSWORD': '', # Not used with sqlite3.
+ 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# On Unix systems, a value of None will cause Django to use the same
+# timezone as the operating system.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Warsaw'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'pl'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# If you set this to False, Django will not format dates, numbers and
+# calendars according to the current locale
+USE_L10N = True
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/home/media/media.lawrence.com/media/"
+MEDIA_ROOT = os.path.join(PROJECT_ROOT, '../media')
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash.
+# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
+MEDIA_URL = ''
+
+# Absolute path to the directory static files should be collected to.
+# Don't put anything in this directory yourself; store your static files
+# in apps' "static/" subdirectories and in STATICFILES_DIRS.
+# Example: "/home/media/media.lawrence.com/static/"
+STATIC_ROOT = ''
+
+# URL prefix for static files.
+# Example: "http://media.lawrence.com/static/"
+STATIC_URL = '/static/'
+
+# URL prefix for admin static files -- CSS, JavaScript and images.
+# Make sure to use a trailing slash.
+# Examples: "http://foo.com/static/admin/", "/static/admin/".
+ADMIN_MEDIA_PREFIX = '/static/admin/'
+
+# Additional locations of static files
+STATICFILES_DIRS = (
+ # Put strings here, like "/home/html/static" or "C:/www/django/static".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+)
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '8ehk^-+pr(o)k6lh_gl9+ks6gkd9u#fka7fv%ikpk(c%llqa6%'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+# 'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+)
+
+ROOT_URLCONF = 'audiobooks.urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ # Uncomment the next line to enable the admin:
+ 'django.contrib.admin',
+ # Uncomment the next line to enable admin documentation:
+ # 'django.contrib.admindocs',
+
+ 'south',
+ 'archive',
+)
+
+# A sample logging configuration. The only tangible logging
+# performed by this configuration is to send an email to
+# the site admins on every HTTP 500 error.
+# See http://docs.djangoproject.com/en/dev/topics/logging for
+# more details on how to customize your logging configuration.
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'class': 'django.utils.log.AdminEmailHandler'
+ }
+ },
+ 'loggers': {
+ 'django.request': {
+ 'handlers': ['mail_admins'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ }
+}
+
+
+
+try:
+ from localsettings import *
+except:
+ pass
--- /dev/null
+from django.conf.urls.defaults import patterns, include, url
+
+# Uncomment the next two lines to enable the admin:
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+ url(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'archive/'}),
+ url(r'^archive/', include('archive.urls')),
+
+ url(r'^admin/', include(admin.site.urls)),
+)
--- /dev/null
+django>=1.3
+django-jsonfield
+South>=0.7
+
+mutagen