Commits

Luke Plant committed 8f57998

Routines to read/write sermon metadata from MP3s

This allows us to write the sermon DB to MP3s, upload the MP3s, then restore
into DB.

  • Participants
  • Parent commits b5952a6

Comments (0)

Files changed (4)

 pytz>=2010b
 semanticeditor==0.2.1
 django-pagination
+mutagen>=1.19

sermons/management/commands/import_sermons.py

 from django.core.management.base import BaseCommand
 
 from sermons.models import Sermon, SERMONS_PATH
-from sermons.tags import set_attrs_from_filename
+from sermons.tags import set_attrs_from_filename, set_attrs_from_id3_tags
 
 class Command(BaseCommand):
 
         sermon_dir = os.path.join(settings.MEDIA_ROOT, SERMONS_PATH)
         sermons = []
         errors = []
+        topics = []
         for f in os.listdir(sermon_dir):
             if f.endswith('.mp3'):
                 s = Sermon(sermon=os.path.join(SERMONS_PATH, f))
-                set_attrs_from_filename(s)
+                # topics have to be set after saving, so they
+                # are returned from set_attrs_from_id3_tags for later processing
+                good_info, topics_to_add = set_attrs_from_id3_tags(s)
+                if not good_info:
+                    set_attrs_from_filename(s)
+                    self.stderr.write("Falling back to filename for %s\n" % os.path.basename(f))
                 try:
                     s.full_clean()
                     s.published = True
                     sermons.append(s)
+                    topics.append(topics_to_add)
                 except ValidationError as e:
                     errors.append("%s could not be imported due to missing/bad data for fields: %s" % (f, ','.join(e.message_dict.keys())))
 
             for e in errors:
                 self.stderr.write(e + '\n')
         else:
-            for s in sermons:
-                if Sermon.objects.filter(date_delivered=s.date_delivered, time_delivered=s.time_delivered).exists():
-                    self.stderr.write("Skipping duplicate: %s\n" % s.sermon.url)
+            for s, ts in zip(sermons, topics):
+                if Sermon.objects.filter(date_delivered=s.date_delivered, time_delivered=s.time_delivered, speaker__name=s.speaker.name).exists():
+                    self.stderr.write("Skipping duplicate: %s\n" % os.path.basename(s.sermon.file.name))
                 else:
-                    self.stdout.write("Importing sermon:   %s\n" % s.sermon.url)
                     s.save()
+                    for t in ts:
+                        s.topics.add(t)

sermons/management/commands/write_ID3_tags.py

+"""
+write_ID3_tags command.
+"""
+from django.core.management.base import BaseCommand
+
+from sermons.models import Sermon
+from sermons.tags import write_id3_tags
+
+class Command(BaseCommand):
+
+    def handle(self, *args, **options):
+        for sermon in Sermon.objects.all():
+            write_id3_tags(sermon)
 from datetime import date, time
 import os
 import re
+import sys
 
-from sermons.models import BIBLE_BOOKS, BIBLE_NAME_TO_VAL, Speaker
+from mutagen.id3 import ID3, TIT2, TDRC, TPE1, TIME, COMM
+
+from sermons.models import BIBLE_BOOKS, BIBLE_NAME_TO_VAL, Speaker, Series, Topic
 
 
 expected_filename_re = re.compile(ur'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}) (?P<hour>\d{2})(?P<minute>\d{2}) (?P<speaker>[^-]+)( - (?P<title>.*))?\.mp3')
     else:
         return False
 
+
+def write_id3_tags(sermon):
+    fname = sermon.sermon.file.name
+    UTF8 = 3 # mutagen.id3 says so.
+    tags = ID3(fname)
+    tags.add(TIT2(encoding=UTF8, text=sermon.title))
+    tags.add(TDRC(encoding=UTF8, text=
+                  sermon.date_delivered.strftime('%Y-%m-%d') + ' ' +
+                  sermon.time_delivered.strftime('%H:%M')))
+    tags.add(TPE1(encoding=UTF8, text=sermon.speaker.name))
+    if sermon.bible_book != '':
+        tags.add(COMM(encoding=UTF8, lang='eng', desc='Sermon.bible_book', text=sermon.bible_book))
+    if sermon.passage != '':
+        tags.add(COMM(encoding=UTF8, lang='eng', desc='Sermon.passage', text=sermon.passage))
+    if sermon.series is not None:
+        tags.add(COMM(encoding=UTF8, lang='eng', desc='Sermon.series', text=sermon.series.name))
+    topics = sermon.topics.all()
+    if len(topics) > 0:
+        tags.add(COMM(encoding=UTF8, lang='eng', desc='Sermon.topics', text=u','.join(
+                    t.name for t in topics)))
+    comment = ("""
+Sermon:
+ Speaker: %(speaker)s
+ Bible book: %(bible_book)s
+ Text: %(passage)s
+ Series: %(series)s
+ Topics: %(topics)s
+""" % dict(speaker=sermon.speaker.name,
+           bible_book=sermon.bible_book,
+           passage=sermon.passage,
+           series=sermon.series.name if sermon.series is not None else '',
+           topics=', '.join(t.name for t in topics) if topics else ''))
+
+    tags.add(COMM(encoding=UTF8, lang='eng', text=comment))
+    tags.save()
+
+def set_attrs_from_id3_tags(sermon):
+    fname = sermon.sermon.file.name
+    tags = ID3(fname)
+
+    title = 'TIT2'
+    date_delivered = 'TDRC'
+    speaker = 'TPE1'
+    bible_book = "COMM:Sermon.bible_book:'eng'"
+    passage = "COMM:Sermon.passage:'eng'"
+    series = "COMM:Sermon.series:'eng'"
+    topics = "COMM:Sermon.topics:'eng'"
+
+    has_time = False
+    if title in tags:
+        sermon.title = tags[title].text[0]
+    if date_delivered in tags:
+        timestamp = tags[date_delivered].text[0]
+        if timestamp.year and timestamp.month and timestamp.day:
+            sermon.date_delivered = date(timestamp.year, timestamp.month, timestamp.day)
+        if timestamp.hour is not None and timestamp.minute is not None:
+            has_time = True
+            sermon.time_delivered = time(timestamp.hour, timestamp.minute)
+    if speaker in tags:
+        sermon.speaker = Speaker.objects.get_or_create(name=tags[speaker].text[0])[0]
+
+    if bible_book in tags:
+        sermon.bible_book = tags[bible_book].text[0]
+
+    if passage in tags:
+        sermon.passage = tags[passage].text[0]
+
+    if series in tags:
+        sermon.series = Series.objects.get_or_create(name=tags[series].text[0])[0]
+
+    topics_to_add = []
+    if topics in tags:
+        for t in tags[topics].text[0].split(','):
+            # Topics have to be added later, after saving
+            topics_to_add.append(Topic.objects.get_or_create(name=t)[0])
+
+    if has_time:
+        # Obviously have done export to ID3, so ID3 has good info.
+        good_info = True
+    else:
+        good_info = False
+    return good_info, topics_to_add