Files
mopidy-webhooks/tests/test_metadata.py

187 lines
5.6 KiB
Python

import json
import shutil
from pathlib import Path
import pytest
from mutagen import File as MutagenFile
from mutagen.id3 import COMM, WXXX
from mopidy_webhooks import metadata
DATA_DIR = Path(__file__).parent / "data"
@pytest.fixture
def tagged_episode(tmp_path):
episode = tmp_path / "2026-09-22 Episode One.mp3"
shutil.copy(DATA_DIR / "silence.mp3", episode)
audio = MutagenFile(episode, easy=True)
audio["title"] = ["Episode One"]
audio["artist"] = ["Jane Host"]
audio["album"] = ["The Test Podcast"]
audio["tracknumber"] = ["42"]
audio["date"] = ["2026-09-22"]
audio["genre"] = ["Technology"]
audio.save()
raw = MutagenFile(episode)
raw.tags.add(
COMM(encoding=3, lang="eng", desc="", text="A tag description")
)
raw.tags.add(WXXX(encoding=3, desc="", url="https://example.com/episode"))
raw.save()
return episode
def test_resolve_media_path_for_file_uri(tagged_episode):
path = metadata.resolve_media_path(tagged_episode.as_uri(), [])
assert path == str(tagged_episode)
def test_resolve_media_path_for_local_uri(tagged_episode, tmp_path):
uri = f"local:podcast:{tagged_episode.name}"
path = metadata.resolve_media_path(uri, [str(tmp_path)])
assert path == str(tagged_episode)
def test_resolve_media_path_for_local_track_uri(tagged_episode, tmp_path):
uri = f"local:track:{tagged_episode.name}"
path = metadata.resolve_media_path(uri, [str(tmp_path)])
assert path == str(tagged_episode)
def test_resolve_media_path_percent_decodes_uri(tagged_episode, tmp_path):
uri = "local:podcast:2026-09-22%20Episode%20One.mp3"
path = metadata.resolve_media_path(uri, [str(tmp_path)])
assert path == str(tagged_episode)
def test_resolve_media_path_returns_none_for_remote_uri():
assert metadata.resolve_media_path("spotify:track:123", []) is None
assert (
metadata.resolve_media_path("podcast+https://example.com/feed#1", [])
is None
)
assert metadata.resolve_media_path("", []) is None
def test_read_tags_returns_normalized_metadata(tagged_episode):
tags = metadata.read_tags(str(tagged_episode))
assert tags["title"] == "Episode One"
assert tags["artist"] == "Jane Host"
assert tags["album"] == "The Test Podcast"
assert tags["track_number"] == "42"
assert tags["date"] == "2026-09-22"
assert tags["genre"] == "Technology"
assert tags["comment"] == "A tag description"
assert tags["website"] == "https://example.com/episode"
def test_read_tags_handles_missing_file():
assert metadata.read_tags("/does/not/exist.mp3") == {}
assert metadata.read_tags(None) == {}
def test_read_sidecar_json_prefers_same_directory(tagged_episode):
sidecar = tagged_episode.with_suffix(".json")
sidecar.write_text(json.dumps({"feed_url": "https://example.com/feed"}))
data = metadata.read_sidecar_json(str(tagged_episode))
assert data["feed_url"] == "https://example.com/feed"
def test_read_metadata_merges_sidecar_and_tags(tagged_episode, tmp_path):
metadata_dir = tmp_path / "metadata"
metadata_dir.mkdir()
sidecar = metadata_dir / f"{tagged_episode.stem}.json"
sidecar.write_text(
json.dumps(
{
"title": "Sidecar Title",
"date": "2026-09-21T10:00:00",
"feed_url": "https://example.com/feed",
"guid": "episode-guid",
"episode_url": "https://example.com/episode.mp3",
"description": "A sidecar description",
"duration": 1234,
}
)
)
data = metadata.read_metadata(str(tagged_episode))
assert data["title"] == "Episode One"
assert data["artist"] == "Jane Host"
assert data["album"] == "The Test Podcast"
assert data["feed_url"] == "https://example.com/feed"
assert data["guid"] == "episode-guid"
assert data["episode_url"] == "https://example.com/episode.mp3"
assert data["description"] == "A sidecar description"
assert data["duration"] == 1234
assert data["date"] == "2026-09-21T10:00:00"
@pytest.mark.parametrize(
"value,expected",
[
("2026-09-22", "2026-09-22"),
("2026-09-22T10:00:00", "2026-09-22"),
("2026-09", "2026-09-01"),
("2026", ""),
("", ""),
("not a date", ""),
],
)
def test_normalize_date(value, expected):
assert metadata.normalize_date(value) == expected
def test_normalize_date_handles_date_objects():
import datetime
assert metadata.normalize_date(datetime.date(2026, 9, 22)) == "2026-09-22"
def test_split_podcast_uri():
feed, guid = metadata.split_podcast_uri(
"podcast+https://feed.example/rss#abc"
)
assert feed == "https://feed.example/rss"
assert guid == "abc"
assert metadata.split_podcast_uri("local:track:foo.mp3") == (None, None)
def test_parse_dirs():
assert metadata.parse_dirs("/a, /b ,, ") == ["/a", "/b"]
assert metadata.parse_dirs("") == []
assert metadata.parse_dirs(None) == []
assert metadata.parse_dirs(["/a", "/b"]) == ["/a", "/b"]
def test_is_podcast_detection(tagged_episode, tmp_path):
assert metadata.is_podcast("local:podcast:foo.mp3")
assert metadata.is_podcast("podcast+https://feed.example/rss#abc")
assert metadata.is_podcast("file:///media/podcasts/foo.mp3")
assert metadata.is_podcast(
"file:///tmp/foo.mp3",
path=str(tagged_episode),
podcast_dirs=[str(tmp_path)],
)
assert metadata.is_podcast(
"file:///tmp/foo.mp3", path="/tmp/foo.mp3", metadata={"feed_url": "x"}
)
assert not metadata.is_podcast(
"local:track:Artist/Album/01%20Song.mp3",
path="/tmp/song.mp3",
)