Skip to content
Snippets Groups Projects
Commit 59cead42 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch '622-deezer-date' into 'develop'

Fix #622: More resilient date parsing during audio import, will not crash anymore on

Closes #622

See merge request !479
parents 0c64b14f 8e84e2bf
No related branches found
No related tags found
No related merge requests found
import datetime import datetime
import logging
import mutagen import mutagen
import pendulum import pendulum
from django import forms from django import forms
logger = logging.getLogger(__name__)
NODEFAULT = object() NODEFAULT = object()
...@@ -14,6 +17,10 @@ class UnsupportedTag(KeyError): ...@@ -14,6 +17,10 @@ class UnsupportedTag(KeyError):
pass pass
class ParseError(ValueError):
pass
def get_id3_tag(f, k): def get_id3_tag(f, k):
if k == "pictures": if k == "pictures":
return f.tags.getall("APIC") return f.tags.getall("APIC")
...@@ -103,8 +110,22 @@ class FirstUUIDField(forms.UUIDField): ...@@ -103,8 +110,22 @@ class FirstUUIDField(forms.UUIDField):
def get_date(value): def get_date(value):
parsed = pendulum.parse(str(value)) ADDITIONAL_FORMATS = ["%Y-%d-%m %H:%M"] # deezer date format
return datetime.date(parsed.year, parsed.month, parsed.day) try:
parsed = pendulum.parse(str(value))
return datetime.date(parsed.year, parsed.month, parsed.day)
except pendulum.exceptions.ParserError:
pass
for date_format in ADDITIONAL_FORMATS:
try:
parsed = datetime.datetime.strptime(value, date_format)
except ValueError:
continue
else:
return datetime.date(parsed.year, parsed.month, parsed.day)
raise ParseError("{} cannot be parsed as a date".format(value))
def split_and_return_first(separator): def split_and_return_first(separator):
...@@ -275,7 +296,7 @@ class Metadata(object): ...@@ -275,7 +296,7 @@ class Metadata(object):
v = field.to_python(v) v = field.to_python(v)
return v return v
def all(self): def all(self, ignore_parse_errors=True):
""" """
Return a dict containing all metadata of the file Return a dict containing all metadata of the file
""" """
...@@ -286,6 +307,11 @@ class Metadata(object): ...@@ -286,6 +307,11 @@ class Metadata(object):
data[field] = self.get(field, None) data[field] = self.get(field, None)
except (TagNotFound, forms.ValidationError): except (TagNotFound, forms.ValidationError):
data[field] = None data[field] = None
except ParseError as e:
if not ignore_parse_errors:
raise
logger.warning("Unparsable field {}: {}".format(field, str(e)))
data[field] = None
return data return data
......
...@@ -196,7 +196,31 @@ def test_mbid_clean_keeps_only_first(field_name): ...@@ -196,7 +196,31 @@ def test_mbid_clean_keeps_only_first(field_name):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"raw,expected", "raw,expected",
[("2017", datetime.date(2017, 1, 1)), ("2017-12-31", datetime.date(2017, 12, 31))], [
("2017", datetime.date(2017, 1, 1)),
("2017-12-31", datetime.date(2017, 12, 31)),
("2017-14-01 01:32", datetime.date(2017, 1, 14)), # deezer format
],
) )
def test_date_parsing(raw, expected): def test_date_parsing(raw, expected):
assert metadata.get_date(raw) == expected assert metadata.get_date(raw) == expected
def test_date_parsing_failure():
with pytest.raises(metadata.ParseError):
metadata.get_date("noop")
def test_metadata_all_ignore_parse_errors_true(mocker):
path = os.path.join(DATA_DIR, "sample.flac")
data = metadata.Metadata(path)
mocker.patch.object(data, "get", side_effect=metadata.ParseError("Failure"))
assert data.all()["date"] is None
def test_metadata_all_ignore_parse_errors_false(mocker):
path = os.path.join(DATA_DIR, "sample.flac")
data = metadata.Metadata(path)
mocker.patch.object(data, "get", side_effect=metadata.ParseError("Failure"))
with pytest.raises(metadata.ParseError):
data.all(ignore_parse_errors=False)
More resilient date parsing during audio import, will not crash anymore on
invalid dates (#622)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment