Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ entries = client.get_entries(category_id=456, status=['read', 'unread'])
# Update entry title and content
client.update_entry(entry_id=1234, title="New title", content="New content")

# Import an entry with a Unix timestamp
client.import_entry(feed_id=123, url="https://example.org/article", published_at=1736200000)

# Update a feed category
client.update_feed(123, category_id=456)

Expand Down Expand Up @@ -136,6 +139,7 @@ The following methods are available on the `miniflux.Client` object:
- `flush_history()`
- `get_feed_entry(feed_id: int, entry_id: int)`
- `get_feed_entries(feed_id: int, **kwargs)`
- `import_entry(feed_id: int, url: str, **kwargs)`
- `mark_feed_entries_as_read(feed_id: int)`
- `get_entry(entry_id: int)`
- `get_entries(**kwargs)`
Expand Down
83 changes: 78 additions & 5 deletions miniflux.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,14 @@ def __init__(
ValueError: If neither `api_key` nor both `username` and `password` are provided.
"""
if not base_url.startswith(("http://", "https://")):
raise ValueError("base_url must be a valid URL starting with http:// or https://")
raise ValueError(
"base_url must be a valid URL starting with http:// or https://"
)

if not api_key and not (username and password):
raise ValueError("Either api_key or both username and password must be provided")
raise ValueError(
"Either api_key or both username and password must be provided"
)

self._base_url = base_url.rstrip("/")
self._timeout = timeout
Expand Down Expand Up @@ -387,7 +391,9 @@ def get_icon_by_feed_id(self, feed_id: int) -> dict:
"""
return self.get_feed_icon(feed_id)

def create_feed(self, feed_url: str, category_id: Optional[int] = None, **kwargs) -> int:
def create_feed(
self, feed_url: str, category_id: Optional[int] = None, **kwargs
) -> int:
"""
Create a new feed.

Expand Down Expand Up @@ -537,6 +543,69 @@ def get_feed_entries(self, feed_id: int, **kwargs) -> dict:
return response.json()
self._handle_error_response(response)

def import_entry(
self,
feed_id: int,
url: str,
title: Optional[str] = None,
author: Optional[str] = None,
content: Optional[str] = None,
published_at: Optional[int] = None,
status: Optional[str] = None,
starred: Optional[bool] = None,
tags: Optional[List[str]] = None,
external_id: Optional[str] = None,
comments_url: Optional[str] = None,
) -> dict:
"""
Import an entry into the given feed.

Args:
feed_id (int): The feed ID.
url (str): The entry URL (required by the API).
title (str): The entry title.
author (str): The entry author.
content (str): The entry content.
published_at (int): The publication date as a Unix timestamp.
status (str): The entry status (read, unread or removed).
starred (bool): Whether the entry is starred.
tags (list[str]): Optional list of tags.
external_id (str): Optional external identifier.
comments_url (str): Optional comments URL.
Returns:
dict: The created entry identifier or existing entry identifier.
Raises:
ValueError: If the URL is empty.
ClientError: If the request fails.
"""
if not url:
raise ValueError("url is required")

endpoint = self._get_endpoint(f"/feeds/{feed_id}/entries/import")
data = self._get_modification_params(
**{
"url": url,
"title": title,
"author": author,
"content": content,
"published_at": published_at,
"status": status,
"starred": starred,
"tags": tags,
"external_id": external_id,
"comments_url": comments_url,
}
)

response = self._session.post(
endpoint,
data=json.dumps(data),
timeout=self._timeout,
)
if response.status_code in (200, 201):
return response.json()
self._handle_error_response(response)

def mark_feed_entries_as_read(self, feed_id: int) -> None:
"""
Mark all entries as read in the given feed.
Expand Down Expand Up @@ -590,7 +659,9 @@ def get_entries(self, **kwargs) -> dict:
return response.json()
self._handle_error_response(response)

def update_entry(self, entry_id: int, title: Optional[str] = None, content: Optional[str] = None) -> dict:
def update_entry(
self, entry_id: int, title: Optional[str] = None, content: Optional[str] = None
) -> dict:
"""
Update an entry.

Expand Down Expand Up @@ -710,7 +781,9 @@ def get_enclosure(self, enclosure_id: int) -> dict:
return response.json()
self._handle_error_response(response)

def update_enclosure(self, enclosure_id: int, media_progression: Optional[int] = None) -> bool:
def update_enclosure(
self, enclosure_id: int, media_progression: Optional[int] = None
) -> bool:
"""
Update an enclosure.

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "miniflux"
version = "1.1.4"
version = "1.1.5"
description = "Client library for Miniflux"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
Loading