Skip to content

Commit 427373e

Browse files
committed
feat: add import_entry method
1 parent e9f0ebb commit 427373e

4 files changed

Lines changed: 355 additions & 61 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ entries = client.get_entries(category_id=456, status=['read', 'unread'])
6262
# Update entry title and content
6363
client.update_entry(entry_id=1234, title="New title", content="New content")
6464

65+
# Import an entry with a Unix timestamp
66+
client.import_entry(feed_id=123, url="https://example.org/article", published_at=1736200000)
67+
6568
# Update a feed category
6669
client.update_feed(123, category_id=456)
6770

@@ -136,6 +139,7 @@ The following methods are available on the `miniflux.Client` object:
136139
- `flush_history()`
137140
- `get_feed_entry(feed_id: int, entry_id: int)`
138141
- `get_feed_entries(feed_id: int, **kwargs)`
142+
- `import_entry(feed_id: int, url: str, **kwargs)`
139143
- `mark_feed_entries_as_read(feed_id: int)`
140144
- `get_entry(entry_id: int)`
141145
- `get_entries(**kwargs)`

miniflux.py

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,14 @@ def __init__(
133133
ValueError: If neither `api_key` nor both `username` and `password` are provided.
134134
"""
135135
if not base_url.startswith(("http://", "https://")):
136-
raise ValueError("base_url must be a valid URL starting with http:// or https://")
136+
raise ValueError(
137+
"base_url must be a valid URL starting with http:// or https://"
138+
)
137139

138140
if not api_key and not (username and password):
139-
raise ValueError("Either api_key or both username and password must be provided")
141+
raise ValueError(
142+
"Either api_key or both username and password must be provided"
143+
)
140144

141145
self._base_url = base_url.rstrip("/")
142146
self._timeout = timeout
@@ -387,7 +391,9 @@ def get_icon_by_feed_id(self, feed_id: int) -> dict:
387391
"""
388392
return self.get_feed_icon(feed_id)
389393

390-
def create_feed(self, feed_url: str, category_id: Optional[int] = None, **kwargs) -> int:
394+
def create_feed(
395+
self, feed_url: str, category_id: Optional[int] = None, **kwargs
396+
) -> int:
391397
"""
392398
Create a new feed.
393399
@@ -537,6 +543,69 @@ def get_feed_entries(self, feed_id: int, **kwargs) -> dict:
537543
return response.json()
538544
self._handle_error_response(response)
539545

546+
def import_entry(
547+
self,
548+
feed_id: int,
549+
url: str,
550+
title: Optional[str] = None,
551+
author: Optional[str] = None,
552+
content: Optional[str] = None,
553+
published_at: Optional[int] = None,
554+
status: Optional[str] = None,
555+
starred: Optional[bool] = None,
556+
tags: Optional[List[str]] = None,
557+
external_id: Optional[str] = None,
558+
comments_url: Optional[str] = None,
559+
) -> dict:
560+
"""
561+
Import an entry into the given feed.
562+
563+
Args:
564+
feed_id (int): The feed ID.
565+
url (str): The entry URL (required by the API).
566+
title (str): The entry title.
567+
author (str): The entry author.
568+
content (str): The entry content.
569+
published_at (int): The publication date as a Unix timestamp.
570+
status (str): The entry status (read, unread or removed).
571+
starred (bool): Whether the entry is starred.
572+
tags (list[str]): Optional list of tags.
573+
external_id (str): Optional external identifier.
574+
comments_url (str): Optional comments URL.
575+
Returns:
576+
dict: The created entry identifier or existing entry identifier.
577+
Raises:
578+
ValueError: If the URL is empty.
579+
ClientError: If the request fails.
580+
"""
581+
if not url:
582+
raise ValueError("url is required")
583+
584+
endpoint = self._get_endpoint(f"/feeds/{feed_id}/entries/import")
585+
data = self._get_modification_params(
586+
**{
587+
"url": url,
588+
"title": title,
589+
"author": author,
590+
"content": content,
591+
"published_at": published_at,
592+
"status": status,
593+
"starred": starred,
594+
"tags": tags,
595+
"external_id": external_id,
596+
"comments_url": comments_url,
597+
}
598+
)
599+
600+
response = self._session.post(
601+
endpoint,
602+
data=json.dumps(data),
603+
timeout=self._timeout,
604+
)
605+
if response.status_code in (200, 201):
606+
return response.json()
607+
self._handle_error_response(response)
608+
540609
def mark_feed_entries_as_read(self, feed_id: int) -> None:
541610
"""
542611
Mark all entries as read in the given feed.
@@ -590,7 +659,9 @@ def get_entries(self, **kwargs) -> dict:
590659
return response.json()
591660
self._handle_error_response(response)
592661

593-
def update_entry(self, entry_id: int, title: Optional[str] = None, content: Optional[str] = None) -> dict:
662+
def update_entry(
663+
self, entry_id: int, title: Optional[str] = None, content: Optional[str] = None
664+
) -> dict:
594665
"""
595666
Update an entry.
596667
@@ -710,7 +781,9 @@ def get_enclosure(self, enclosure_id: int) -> dict:
710781
return response.json()
711782
self._handle_error_response(response)
712783

713-
def update_enclosure(self, enclosure_id: int, media_progression: Optional[int] = None) -> bool:
784+
def update_enclosure(
785+
self, enclosure_id: int, media_progression: Optional[int] = None
786+
) -> bool:
714787
"""
715788
Update an enclosure.
716789

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "miniflux"
3-
version = "1.1.4"
3+
version = "1.1.5"
44
description = "Client library for Miniflux"
55
readme = "README.md"
66
requires-python = ">=3.8"

0 commit comments

Comments
 (0)