libretime/worker/tests/tasks_test.py
Jonas L. 107bacf296
fix(worker): catch mutagen TypeError when saving metadata (#3182)
Mutagen may fail with:

```
worker-1  | Traceback (most recent call last):
worker-1  |   File "/usr/local/lib/python3.10/site-packages/celery/app/trace.py", line 412, in trace_task
worker-1  |     R = retval = fun(*args, **kwargs)
worker-1  |   File "/usr/local/lib/python3.10/site-packages/celery/app/trace.py", line 704, in __protected_call__
worker-1  |     return self.run(*args, **kwargs)
worker-1  |   File "/src/libretime_worker/tasks.py", line 114, in podcast_download
worker-1  |     metadata["artist"] = podcast_name
worker-1  |   File "/usr/local/lib/python3.10/site-packages/mutagen/_file.py", line 74, in __setitem__
worker-1  |     self.tags[key] = value
worker-1  |   File "/usr/local/lib/python3.10/site-packages/mutagen/id3/_tags.py", line 341, in __setitem__
worker-1  |     raise TypeError("%r not a Frame instance" % tag)
worker-1  | TypeError: "Infos du soir" not a Frame instance
```

This TypeError was raised when I trying to write metadata to a wave
file.

This patch ensures that the error is reported back to the frontend. It
also improve the error messages being reported.
2025-07-16 20:24:02 +02:00

79 lines
2.1 KiB
Python

import json
import pytest
from requests import Response
from libretime_worker.tasks import extract_filename, podcast_download
from .fixtures import fixtures_path
@pytest.mark.parametrize(
"file",
[
("s1-stereo.ogg"),
("s1-stereo-tagged.mp3"),
("malformed.mp3"),
],
)
@pytest.mark.parametrize("override_album", [(True), (False)])
def test_podcast_download(requests_mock, file, override_album):
episode_url = f"https://remote.example.org/{file}"
episode_filepath = fixtures_path / file
requests_mock.get(episode_url, content=episode_filepath.read_bytes())
requests_mock.post("http://localhost/rest/media", json={"id": 1})
result = podcast_download(
episode_id=1,
episode_url=episode_url,
episode_title="My episode",
podcast_name="My podcast!",
override_album=override_album,
)
assert json.loads(result) == {
"episodeid": 1,
"fileid": 1,
"status": 1,
}
def test_podcast_download_invalid_file(requests_mock):
episode_url = "https://remote.example.org/invalid"
requests_mock.get(episode_url, content=b"some invalid content")
requests_mock.post("http://localhost/rest/media", json={"id": 1})
result = podcast_download(
episode_id=1,
episode_url=episode_url,
episode_title="My episode",
podcast_name="My podcast!",
override_album=False,
)
assert json.loads(result) == {
"episodeid": 1,
"status": 0,
"error": "could not determine podcast episode 1 file type",
}
@pytest.mark.parametrize(
"url, header, expected",
[
("http://example.com/from-url.mp3", None, "from-url.mp3"),
(
"http://example.com/from-url.mp3",
'attachment; filename="from-header.mp3"',
"from-header.mp3",
),
("http://example.com/from-url.mp3", "attachment", "from-url.mp3"),
],
)
def test_extract_filename(url, header, expected):
resp = Response()
resp.url = url
if header is not None:
resp.headers["Content-Disposition"] = header
assert extract_filename(resp) == expected