From 02dd95d005be7fb93daf8161f6cfc7f65093f029 Mon Sep 17 00:00:00 2001 From: Jan Willhaus Date: Sun, 22 Sep 2024 11:07:22 +0200 Subject: [PATCH] feat: Add support for file url scheme (#183) Closes #179 --- README.md | 6 ++++++ podcast_archiver/models.py | 10 +++++++--- tests/conftest.py | 5 +++++ tests/test_fetch.py | 22 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/test_fetch.py diff --git a/README.md b/README.md index f905db7..adeab2e 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,12 @@ podcast-archiver -d ~/Music/Podcasts \ This way, you can easily add and remove feeds to the list and let the archiver fetch the newest episodes for example by adding it to your crontab. +Feeds can also be "fetched" from a local file: + +```bash +podcast-archiver -f file:/Users/janw/downloaded_feed.xml +``` + ### Changing the filename format Podcast Archiver has a `--filename-template` option that allows you to change the particular naming scheme of the archive. The default value for `--filename-template`. is shown in `podcast-archiver --help`, as well as all the available variables. The basic ones are: diff --git a/podcast_archiver/models.py b/podcast_archiver/models.py index cd5c2d0..919f14b 100644 --- a/podcast_archiver/models.py +++ b/podcast_archiver/models.py @@ -163,9 +163,13 @@ class FeedPage(BaseModel): @classmethod def from_url(cls, url: str) -> FeedPage: - response = session.get(url, allow_redirects=True, timeout=REQUESTS_TIMEOUT) - response.raise_for_status() - feedobj = feedparser.parse(response.content) + parsed = urlparse(url) + if parsed.scheme == "file": + feedobj = feedparser.parse(parsed.path) + else: + response = session.get(url, allow_redirects=True, timeout=REQUESTS_TIMEOUT) + response.raise_for_status() + feedobj = feedparser.parse(response.content) return cls.model_validate(feedobj) diff --git a/tests/conftest.py b/tests/conftest.py index e3f6cb0..e14570a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -33,6 +33,11 @@ def feed_lautsprecher(responses: RequestsMock) -> str: return FEED_URL +@pytest.fixture +def feed_lautsprecher_file() -> str: + return f'file:{FIXTURES_DIR/ "feed_lautsprecher.xml"}' + + @pytest.fixture def feed_lautsprecher_notconsumed(responses: RequestsMock) -> str: return FEED_URL diff --git a/tests/test_fetch.py b/tests/test_fetch.py new file mode 100644 index 0000000..7ff6540 --- /dev/null +++ b/tests/test_fetch.py @@ -0,0 +1,22 @@ +from pathlib import Path + +import pytest + +from podcast_archiver.models import Feed + +FILE_FIXTURE = Path(__file__).parent / "fixtures" / "feed_lautsprecher.xml" + + +def test_fetch_from_http(feed_lautsprecher_onlyfeed: str) -> None: + assert Feed.from_url(feed_lautsprecher_onlyfeed) + + +@pytest.mark.parametrize( + "url", + [ + f"file:{FILE_FIXTURE}", + f"file://{FILE_FIXTURE}", + ], +) +def test_fetch_from_file(url: str) -> None: + assert Feed.from_url(url)