Follows: followed tags/pools, feeds, unseen badges and blacklist cloud
Backend (new apps.follows): - FollowedTag/FollowedPool/FollowedPost models; per-user follows with unseen tracking, plus FollowCloud for the cached blacklist cloud. - Two periodic commands sharing one fetch path: sync_followed_tags and sync_followed_pools fetch each followed tag/pool's newest posts (one e621 search per unique follow), store unseen feed rows, refresh covers and pool metadata; both fall back to anonymous e621 access. - API: /api/follows/tags|pools (follow, unfollow, mark seen), a merged feed with per-follow filtering, and /api/follows/cloud/ which rebuilds the blacklisted-tag cloud in a daemon thread when its 10 min cache is stale (polling returns building/ready). - e621 client now supports anonymous reads; trimmed posts carry preview URLs for covers and feed tiles. Frontend: - /followed page: follow forms, cover cards with unseen badges and Mark seen, merged feed with filter/unseen toggle, and a blacklist cloud panel that polls while building. Followed nav entry added.
This commit is contained in:
@@ -41,13 +41,17 @@ def _wait_for_slot():
|
||||
_last_request_at = time.monotonic()
|
||||
|
||||
|
||||
def get(user, path, params=None, timeout=30):
|
||||
def get(user, path, params=None, timeout=30, require_auth=True):
|
||||
"""GET an e621 API path using the user's credentials.
|
||||
|
||||
Reads that e621 serves anonymously (searches, pools, tags) can pass
|
||||
require_auth=False; matching endpoints keep requiring credentials.
|
||||
|
||||
Raises E621NotFound for 404s and E621Error for everything else that isn't
|
||||
a 2xx, so callers never see requests exceptions.
|
||||
"""
|
||||
if not credentials_configured(user):
|
||||
configured = credentials_configured(user)
|
||||
if require_auth and not configured:
|
||||
raise E621Error("Configure your e621 credentials in Account first.")
|
||||
base = (getattr(user, "e621_base_url", "") or "https://e621.net").rstrip("/")
|
||||
_wait_for_slot()
|
||||
@@ -55,7 +59,7 @@ def get(user, path, params=None, timeout=30):
|
||||
response = requests.get(
|
||||
f"{base}{path}",
|
||||
params=params,
|
||||
auth=(user.e621_username, user.e621_api_key),
|
||||
auth=(user.e621_username, user.e621_api_key) if configured else None,
|
||||
headers={"User-Agent": settings.USER_AGENT},
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
@@ -323,6 +323,9 @@ def trim_e621_post(post):
|
||||
"height": file_data.get("height"),
|
||||
"url": file_data.get("url"),
|
||||
},
|
||||
"preview": {
|
||||
"url": (post.get("preview") or {}).get("url"),
|
||||
},
|
||||
"uploader_name": post.get("uploader_name"),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user