Data Models Reference
Entry
The Entry class represents a single RSS entry/article.
Represents a Miniflux feed entry.
Source code in miniflux_tui/api/models.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 | @dataclass
class Entry:
"""Represents a Miniflux feed entry."""
id: int
feed_id: int
title: str
url: str
content: str
feed: Feed
status: str # "read" or "unread"
starred: bool
published_at: datetime
original_content: str | None = None
enclosures: list[Enclosure] | None = None
@classmethod
def from_dict(cls, data: dict) -> "Entry":
"""Create an Entry from API response data.
Raises:
KeyError: If the entry or its feed has no ``id``
TypeError: If ``feed`` or ``enclosures`` have the wrong shape
"""
# Parse enclosures if present; skip malformed ones rather than fail the entry
enclosures: list[Enclosure] | None = None
raw_enclosures = data.get("enclosures")
if isinstance(raw_enclosures, list) and raw_enclosures:
enclosures = []
for raw in raw_enclosures:
if isinstance(raw, dict) and "id" in raw:
enclosures.append(Enclosure.from_dict(raw))
feed_data = data.get("feed")
feed_id = _as_int(data.get("feed_id"), default=-1)
if not isinstance(feed_data, dict):
if feed_id < 0:
msg = "feed"
raise KeyError(msg)
feed_data = {"id": feed_id}
feed = Feed.from_dict(feed_data)
original_content = data.get("original_content")
return cls(
id=_as_int(data["id"]),
feed_id=feed.id if feed_id < 0 else feed_id,
title=_as_str(data.get("title")),
url=_as_str(data.get("url")),
content=_as_str(data.get("content")),
feed=feed,
status=_as_str(data.get("status"), default="unread"),
starred=_as_bool(data.get("starred")),
published_at=_parse_datetime(data.get("published_at")),
original_content=_as_str(original_content) if original_content is not None else None,
enclosures=enclosures,
)
@property
def is_read(self) -> bool:
"""Check if entry is marked as read."""
return self.status == "read"
@property
def is_unread(self) -> bool:
"""Check if entry is marked as unread."""
return self.status == "unread"
@property
def image_enclosures(self) -> list[Enclosure]:
"""Get all image enclosures for this entry."""
if not self.enclosures:
return []
return [enc for enc in self.enclosures if enc.is_image]
|
image_enclosures
property
Get all image enclosures for this entry.
is_read
property
Check if entry is marked as read.
is_unread
property
Check if entry is marked as unread.
from_dict(data)
classmethod
Create an Entry from API response data.
Raises:
| Type |
Description |
KeyError
|
If the entry or its feed has no id
|
TypeError
|
If feed or enclosures have the wrong shape
|
Source code in miniflux_tui/api/models.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 | @classmethod
def from_dict(cls, data: dict) -> "Entry":
"""Create an Entry from API response data.
Raises:
KeyError: If the entry or its feed has no ``id``
TypeError: If ``feed`` or ``enclosures`` have the wrong shape
"""
# Parse enclosures if present; skip malformed ones rather than fail the entry
enclosures: list[Enclosure] | None = None
raw_enclosures = data.get("enclosures")
if isinstance(raw_enclosures, list) and raw_enclosures:
enclosures = []
for raw in raw_enclosures:
if isinstance(raw, dict) and "id" in raw:
enclosures.append(Enclosure.from_dict(raw))
feed_data = data.get("feed")
feed_id = _as_int(data.get("feed_id"), default=-1)
if not isinstance(feed_data, dict):
if feed_id < 0:
msg = "feed"
raise KeyError(msg)
feed_data = {"id": feed_id}
feed = Feed.from_dict(feed_data)
original_content = data.get("original_content")
return cls(
id=_as_int(data["id"]),
feed_id=feed.id if feed_id < 0 else feed_id,
title=_as_str(data.get("title")),
url=_as_str(data.get("url")),
content=_as_str(data.get("content")),
feed=feed,
status=_as_str(data.get("status"), default="unread"),
starred=_as_bool(data.get("starred")),
published_at=_parse_datetime(data.get("published_at")),
original_content=_as_str(original_content) if original_content is not None else None,
enclosures=enclosures,
)
|
Properties
- id: Unique identifier for the entry
- title: Entry title
- content: Entry HTML content
- published_at: Publication timestamp
- is_read: Whether the entry has been read
- starred: Whether the entry is starred/favorited
- feed: The Feed this entry belongs to
Helper Methods
- is_unread: Property that returns
True if not read
- status: Property that returns "read" or "unread"
Feed
The Feed class represents an RSS feed.
Represents a Miniflux feed.
Source code in miniflux_tui/api/models.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 | @dataclass
class Feed:
"""Represents a Miniflux feed."""
id: int
title: str
site_url: str
feed_url: str
category_id: int | None = None
description: str = "" # User-provided description or notes for the feed
parsing_error_message: str = ""
parsing_error_count: int = 0
checked_at: str | None = None
disabled: bool = False
# Network settings
username: str = ""
password: str = ""
user_agent: str = ""
proxy_url: str = ""
ignore_https_errors: bool = False
# Rules & filtering (API uses blocklist_rules and keeplist_rules, not blocking_rules and keep_rules)
scraper_rules: str = ""
rewrite_rules: str = ""
blocklist_rules: str = ""
keeplist_rules: str = ""
# Feed behavior options
hide_globally: bool = False
no_media_player: bool = False
# Additional feed settings
crawler: bool = False
ignore_http_cache: bool = False
fetch_via_proxy: bool = False
check_interval: int | None = None
@classmethod
def from_dict(cls, data: dict) -> "Feed":
"""Create a Feed from API response data."""
checked_at = data.get("checked_at")
return cls(
id=_as_int(data["id"]),
title=_as_str(data.get("title")),
site_url=_as_str(data.get("site_url")),
feed_url=_as_str(data.get("feed_url")),
category_id=_as_optional_int(data.get("category_id")),
description=_as_str(data.get("description")),
parsing_error_message=_as_str(data.get("parsing_error_message")),
parsing_error_count=_as_int(data.get("parsing_error_count")),
checked_at=_as_str(checked_at) if checked_at is not None else None,
disabled=_as_bool(data.get("disabled")),
username=_as_str(data.get("username")),
password=_as_str(data.get("password")),
user_agent=_as_str(data.get("user_agent")),
proxy_url=_as_str(data.get("proxy_url")),
ignore_https_errors=_as_bool(data.get("ignore_https_errors")),
scraper_rules=_as_str(data.get("scraper_rules")),
rewrite_rules=_as_str(data.get("rewrite_rules")),
blocklist_rules=_as_str(data.get("blocklist_rules")),
keeplist_rules=_as_str(data.get("keeplist_rules")),
hide_globally=_as_bool(data.get("hide_globally")),
no_media_player=_as_bool(data.get("no_media_player")),
crawler=_as_bool(data.get("crawler")),
ignore_http_cache=_as_bool(data.get("ignore_http_cache")),
fetch_via_proxy=_as_bool(data.get("fetch_via_proxy")),
check_interval=_as_optional_int(data.get("check_interval")),
)
@property
def has_errors(self) -> bool:
"""Check if feed has parsing errors."""
return bool(self.parsing_error_message or self.parsing_error_count > 0)
|
has_errors
property
Check if feed has parsing errors.
from_dict(data)
classmethod
Create a Feed from API response data.
Source code in miniflux_tui/api/models.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 | @classmethod
def from_dict(cls, data: dict) -> "Feed":
"""Create a Feed from API response data."""
checked_at = data.get("checked_at")
return cls(
id=_as_int(data["id"]),
title=_as_str(data.get("title")),
site_url=_as_str(data.get("site_url")),
feed_url=_as_str(data.get("feed_url")),
category_id=_as_optional_int(data.get("category_id")),
description=_as_str(data.get("description")),
parsing_error_message=_as_str(data.get("parsing_error_message")),
parsing_error_count=_as_int(data.get("parsing_error_count")),
checked_at=_as_str(checked_at) if checked_at is not None else None,
disabled=_as_bool(data.get("disabled")),
username=_as_str(data.get("username")),
password=_as_str(data.get("password")),
user_agent=_as_str(data.get("user_agent")),
proxy_url=_as_str(data.get("proxy_url")),
ignore_https_errors=_as_bool(data.get("ignore_https_errors")),
scraper_rules=_as_str(data.get("scraper_rules")),
rewrite_rules=_as_str(data.get("rewrite_rules")),
blocklist_rules=_as_str(data.get("blocklist_rules")),
keeplist_rules=_as_str(data.get("keeplist_rules")),
hide_globally=_as_bool(data.get("hide_globally")),
no_media_player=_as_bool(data.get("no_media_player")),
crawler=_as_bool(data.get("crawler")),
ignore_http_cache=_as_bool(data.get("ignore_http_cache")),
fetch_via_proxy=_as_bool(data.get("fetch_via_proxy")),
check_interval=_as_optional_int(data.get("check_interval")),
)
|
Feed Properties
- id: Unique feed identifier
- title: Feed title
- url: Feed URL
- unread_count: Number of unread entries in this feed
EntryListItem
Internal widget class for rendering entries in the list.
Internal widget class for rendering feed group headers in grouped mode.
Usage Example
from miniflux_tui.api.models import Entry, Feed
# Create a feed
feed = Feed(id=1, title="My Blog", url="https://example.com/feed")
# Create an entry
entry = Entry(
id=123, title="My Article", content="<p>Article content</p>", published_at=1699564800, is_read=False, starred=False, feed=feed
)
# Check properties
print(f"Entry: {entry.title}")
print(f"Feed: {entry.feed.title}")
print(f"Status: {entry.status}")
print(f"Is unread: {entry.is_unread}")