Skip to content

Commit

Permalink
Fix Issue #28: mutagen.mp3.HeaderNotFoundError: can't sync to MPEG fr…
Browse files Browse the repository at this point in the history
…ame (#29)

* 🥅 Fix issue #28: catch mutagen.mp3.HeaderNotFoundError while loading podcasts

* this prevents app crash because of single broken/incompatible mp3 files.

* 🥅 Fix "ValueError: year 0 is out of range" error when trying to format date tag as into html

* 🐛 fix UnicodeEncodeError by allowing surrogates in the data while encoding to bytes

* e.g. the following:
     UnicodeEncodeError: 'utf-8' codec can't encode character '\udc84' in position 767364: surrogates not allowed
* ensure request responses are already encoded to bytes to avoid strict encoding by the requests library

* 🔊 add logging for broken file metadata (HeaderNotFoundError)
  • Loading branch information
pokulo authored Sep 13, 2024
1 parent 1ddeda7 commit f68e862
Showing 1 changed file with 20 additions and 4 deletions.
24 changes: 20 additions & 4 deletions podcats/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
or another podcast client.
"""
import datetime
import logging
import os
import re
import time
import argparse
import mimetypes
from email.utils import formatdate
from os import path
from urllib.parse import quote
from xml.sax.saxutils import escape, quoteattr

try:
Expand All @@ -26,6 +29,7 @@
import mutagen
import humanize
from mutagen.id3 import ID3
from mutagen.mp3 import HeaderNotFoundError
from flask import Flask, Response
# noinspection PyPackageRequirements
from jinja2 import Environment, FileSystemLoader
Expand All @@ -43,6 +47,8 @@

jinja2_env = Environment(loader=FileSystemLoader(TEMPLATES_ROOT))

logger = logging.getLogger(__name__)


class Episode(object):
"""Podcast episode"""
Expand All @@ -52,7 +58,13 @@ def __init__(self, filename, relative_dir, root_url):
self.relative_dir = relative_dir
self.root_url = root_url
self.length = os.path.getsize(filename)
self.tags = mutagen.File(self.filename, easy=True)

try:
self.tags = mutagen.File(self.filename, easy=True) or {}
except HeaderNotFoundError as err:
self.tags = {}
logger.warning("Could not load tags of file {filename} due to: {err!r}".format(filename=self.filename, err=err))

try:
self.id3 = ID3(self.filename)
except Exception:
Expand Down Expand Up @@ -87,6 +99,10 @@ def as_html(self):
filename = os.path.basename(self.filename)
directory = os.path.split(os.path.dirname(self.filename))[-1]
template = jinja2_env.get_template('episode.html')
try:
date = formatdate(self.date)
except ValueError:
date = datetime.datetime.now(tz=datetime.timezone.utc)

return template.render(
title=escape(self.title),
Expand All @@ -95,7 +111,7 @@ def as_html(self):
directory=directory,
mimetype=self.mimetype,
length=humanize.naturalsize(self.length),
date=formatdate(self.date),
date=date,
image_url=self.image,
)

Expand All @@ -110,7 +126,7 @@ def _to_url(self, filepath):
fn = os.path.basename(filepath)
path = STATIC_PATH + '/' + self.relative_dir + '/' + fn
path = re.sub(r'//', '/', path)
url = self.root_url + pathname2url(path)
url = self.root_url + quote(path, errors="surrogateescape")
return url

@property
Expand Down Expand Up @@ -225,7 +241,7 @@ def as_html(self):
description=self.description,
link=escape(self.link),
items=u''.join(episode.as_html() for episode in sorted(self)),
).strip()
).strip().encode("utf-8", "surrogateescape")


def serve(channel):
Expand Down

0 comments on commit f68e862

Please # to comment.